blob: a1f5d9ff165009d2c0e23b8199b6b2757aa975f8 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
Janak Ramakrishnane72d5222015-02-26 17:09:18 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.query2;
15
nharmata1bd4aaf2017-10-31 11:23:04 -040016import static com.google.common.collect.ImmutableSet.toImmutableSet;
janakrb8bc2842021-12-08 12:48:02 -080017import static com.google.common.util.concurrent.Futures.immediateVoidFuture;
Googler73b7b2e2017-03-23 17:20:58 +000018import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
shreyax432b2532019-01-23 11:16:07 -080019import static com.google.devtools.build.lib.pkgcache.FilteringPolicies.NO_FILTER;
Googler73b7b2e2017-03-23 17:20:58 +000020
Janak Ramakrishnan36858732015-06-17 16:45:47 +000021import com.google.common.base.Function;
tomlua155b532017-11-08 20:12:47 +010022import com.google.common.base.Preconditions;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000023import com.google.common.base.Predicate;
Janak Ramakrishnanb735d2f2015-06-16 17:46:36 +000024import com.google.common.base.Predicates;
Nathan Harmata79e49652016-12-16 22:00:48 +000025import com.google.common.base.Throwables;
Janak Ramakrishnanf6f0fcc2015-06-19 20:24:52 +000026import com.google.common.collect.ArrayListMultimap;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000027import com.google.common.collect.Collections2;
Janak Ramakrishnancda5b662015-06-18 23:46:36 +000028import com.google.common.collect.ImmutableList;
Janak Ramakrishnan36858732015-06-17 16:45:47 +000029import com.google.common.collect.ImmutableMap;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000030import com.google.common.collect.ImmutableSet;
31import com.google.common.collect.Iterables;
Googlerd1911622016-06-27 15:43:11 +000032import com.google.common.collect.Maps;
Janak Ramakrishnan36858732015-06-17 16:45:47 +000033import com.google.common.collect.Multimap;
Miguel Alcon Pinto933c13a2015-09-16 18:37:45 +000034import com.google.common.collect.Sets;
janakr0fa30222020-04-13 17:38:06 -070035import com.google.common.flogger.GoogleLogger;
Nathan Harmata7a5a2362017-03-08 22:42:01 +000036import com.google.common.util.concurrent.Futures;
37import com.google.common.util.concurrent.ListenableFuture;
38import com.google.common.util.concurrent.ListeningExecutorService;
39import com.google.common.util.concurrent.MoreExecutors;
40import com.google.common.util.concurrent.ThreadFactoryBuilder;
janakrb8bc2842021-12-08 12:48:02 -080041import com.google.devtools.build.lib.bugreport.BugReport;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000042import com.google.devtools.build.lib.cmdline.Label;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000043import com.google.devtools.build.lib.cmdline.PackageIdentifier;
janakrbe525302021-11-16 14:45:58 -080044import com.google.devtools.build.lib.cmdline.ParallelVisitor.VisitTaskStatusCallback;
wyv630be022021-10-04 07:55:36 -070045import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000046import com.google.devtools.build.lib.cmdline.TargetParsingException;
Mark Schallerb889cf32015-03-17 20:55:30 +000047import com.google.devtools.build.lib.cmdline.TargetPattern;
nharmatafbdd5932021-05-20 12:07:09 -070048import com.google.devtools.build.lib.cmdline.TargetPatternResolver;
philwo3bcb9f62017-09-06 12:52:21 +020049import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet;
Nathan Harmata7a5a2362017-03-08 22:42:01 +000050import com.google.devtools.build.lib.concurrent.BlockingStack;
Nathan Harmata41b54172016-11-10 18:54:09 +000051import com.google.devtools.build.lib.concurrent.MultisetSemaphore;
Mark Schaller20c75012016-06-21 22:51:14 +000052import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
Mark Schaller4f48f1b2017-03-10 20:38:43 +000053import com.google.devtools.build.lib.events.DelegatingEventHandler;
Janak Ramakrishnan3533ab52016-01-14 18:14:09 +000054import com.google.devtools.build.lib.events.Event;
Mark Schaller4f48f1b2017-03-10 20:38:43 +000055import com.google.devtools.build.lib.events.EventKind;
Klaus Aehlig777b30d2017-02-24 16:30:15 +000056import com.google.devtools.build.lib.events.ExtendedEventHandler;
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000057import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
Dmitry Lomov6073eb62016-01-21 21:26:32 +000058import com.google.devtools.build.lib.packages.DependencyFilter;
Janak Ramakrishnan112840b2016-12-29 21:49:56 +000059import com.google.devtools.build.lib.packages.NoSuchPackageException;
Janak Ramakrishnan36858732015-06-17 16:45:47 +000060import com.google.devtools.build.lib.packages.NoSuchTargetException;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000061import com.google.devtools.build.lib.packages.NoSuchThingException;
62import com.google.devtools.build.lib.packages.Package;
63import com.google.devtools.build.lib.packages.Rule;
64import com.google.devtools.build.lib.packages.Target;
ulfjacke83775d2019-05-14 08:58:46 -070065import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
Mark Schallerb889cf32015-03-17 20:55:30 +000066import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
Nathan Harmata483ded92016-01-13 19:42:45 +000067import com.google.devtools.build.lib.profiler.AutoProfiler;
janakr30e99152020-04-03 08:01:25 -070068import com.google.devtools.build.lib.profiler.GoogleAutoProfilerUtils;
michajloe7496772019-08-22 16:55:33 -070069import com.google.devtools.build.lib.query2.common.AbstractBlazeQueryEnvironment;
janakra01210f2022-02-17 18:56:01 -080070import com.google.devtools.build.lib.query2.common.QueryTransitivePackagePreloader;
nharmatae294b342020-07-16 17:56:21 -070071import com.google.devtools.build.lib.query2.common.UniverseScope;
janakra3652a32020-09-10 12:05:20 -070072import com.google.devtools.build.lib.query2.common.UniverseSkyKey;
michajloe7496772019-08-22 16:55:33 -070073import com.google.devtools.build.lib.query2.compat.FakeLoadTarget;
Janak Ramakrishnan643063d2015-06-25 16:21:49 +000074import com.google.devtools.build.lib.query2.engine.AllRdepsFunction;
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +000075import com.google.devtools.build.lib.query2.engine.Callback;
Nathan Harmatae9826b42017-03-07 18:05:21 +000076import com.google.devtools.build.lib.query2.engine.KeyExtractor;
77import com.google.devtools.build.lib.query2.engine.MinDepthUniquifier;
Nathan Harmata5bb9cc92016-09-30 21:28:30 +000078import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000079import com.google.devtools.build.lib.query2.engine.QueryEvalResult;
80import com.google.devtools.build.lib.query2.engine.QueryException;
81import com.google.devtools.build.lib.query2.engine.QueryExpression;
shreyax159a6112018-06-12 15:34:09 -070082import com.google.devtools.build.lib.query2.engine.QueryExpressionContext;
Nathan Harmataed935602016-03-02 01:16:14 +000083import com.google.devtools.build.lib.query2.engine.QueryExpressionMapper;
Nathan Harmata7a5a2362017-03-08 22:42:01 +000084import com.google.devtools.build.lib.query2.engine.QueryUtil.MinDepthUniquifierImpl;
nharmatabf2e2d82017-06-21 23:12:51 +020085import com.google.devtools.build.lib.query2.engine.QueryUtil.MutableKeyExtractorBackedMapImpl;
nharmatac49e8742018-09-27 11:27:41 -070086import com.google.devtools.build.lib.query2.engine.QueryUtil.NonExceptionalUniquifier;
nharmatabf2e2d82017-06-21 23:12:51 +020087import com.google.devtools.build.lib.query2.engine.QueryUtil.ThreadSafeMutableKeyExtractorBackedSetImpl;
Nathan Harmata7a5a2362017-03-08 22:42:01 +000088import com.google.devtools.build.lib.query2.engine.QueryUtil.UniquifierImpl;
Googlerd1911622016-06-27 15:43:11 +000089import com.google.devtools.build.lib.query2.engine.StreamableQueryEnvironment;
Nathan Harmata7a5a2362017-03-08 22:42:01 +000090import com.google.devtools.build.lib.query2.engine.ThreadSafeOutputFormatterCallback;
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +000091import com.google.devtools.build.lib.query2.engine.Uniquifier;
gregcea91495f2019-05-07 07:27:39 -070092import com.google.devtools.build.lib.query2.query.BlazeTargetAccessor;
janakrb7fecb92022-02-08 16:52:41 -080093import com.google.devtools.build.lib.server.FailureDetails;
mschaller0f61b362020-08-24 12:59:55 -070094import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
Googler3e3c8312020-07-08 15:41:39 -070095import com.google.devtools.build.lib.server.FailureDetails.Query;
mschaller0f61b362020-08-24 12:59:55 -070096import com.google.devtools.build.lib.server.FailureDetails.Query.Code;
97import com.google.devtools.build.lib.skyframe.DetailedException;
Mark Schallerb889cf32015-03-17 20:55:30 +000098import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider;
John Cater97aebaa2021-04-12 06:10:00 -070099import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider.UniverseTargetPattern;
kkress1847a012020-06-24 12:30:11 -0700100import com.google.devtools.build.lib.skyframe.IgnoredPackagePrefixesValue;
janakrb7fecb92022-02-08 16:52:41 -0800101import com.google.devtools.build.lib.skyframe.PackageLookupValue;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000102import com.google.devtools.build.lib.skyframe.PackageValue;
Janak Ramakrishnan958ef822016-01-07 16:21:39 +0000103import com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternsFunction;
Mark Schallerb889cf32015-03-17 20:55:30 +0000104import com.google.devtools.build.lib.skyframe.RecursivePackageProviderBackedTargetPatternResolver;
nharmatafbdd5932021-05-20 12:07:09 -0700105import com.google.devtools.build.lib.skyframe.SimplePackageIdentifierBatchingCallback;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000106import com.google.devtools.build.lib.skyframe.TargetPatternValue;
Mark Schallerd7311e02015-07-07 16:36:09 +0000107import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000108import com.google.devtools.build.lib.skyframe.TransitiveTraversalValue;
juliexxiacc864752018-06-01 09:03:48 -0700109import com.google.devtools.build.lib.skyframe.TraversalInfoRootPackageExtractor;
Googler407d3932019-05-16 15:13:59 -0700110import com.google.devtools.build.lib.supplier.InterruptibleSupplier;
111import com.google.devtools.build.lib.supplier.MemoizingInterruptibleSupplier;
mschaller0f61b362020-08-24 12:59:55 -0700112import com.google.devtools.build.lib.util.DetailedExitCode;
Janak Ramakrishnand802d5b2015-08-20 21:05:46 +0000113import com.google.devtools.build.lib.vfs.PathFragment;
Googler10028672018-10-25 12:14:34 -0700114import com.google.devtools.build.skyframe.EvaluationContext;
Mark Schallerd7311e02015-07-07 16:36:09 +0000115import com.google.devtools.build.skyframe.EvaluationResult;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000116import com.google.devtools.build.skyframe.SkyFunctionName;
117import com.google.devtools.build.skyframe.SkyKey;
Janak Ramakrishnan36858732015-06-17 16:45:47 +0000118import com.google.devtools.build.skyframe.SkyValue;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000119import com.google.devtools.build.skyframe.WalkableGraph;
120import com.google.devtools.build.skyframe.WalkableGraph.WalkableGraphFactory;
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000121import java.io.IOException;
janakr30e99152020-04-03 08:01:25 -0700122import java.time.Duration;
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +0000123import java.util.ArrayList;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000124import java.util.Collection;
shreyax55bc5212020-01-27 11:46:39 -0800125import java.util.HashMap;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000126import java.util.HashSet;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000127import java.util.List;
128import java.util.Map;
nharmatae294b342020-07-16 17:56:21 -0700129import java.util.Optional;
janakra01210f2022-02-17 18:56:01 -0800130import java.util.OptionalInt;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000131import java.util.Set;
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000132import java.util.concurrent.Callable;
133import java.util.concurrent.RejectedExecutionException;
134import java.util.concurrent.ThreadPoolExecutor;
Nathan Harmata71616b12016-09-28 20:20:48 +0000135import java.util.concurrent.TimeUnit;
nharmata641db6d2018-08-16 14:31:57 -0700136import java.util.function.BiConsumer;
shreyax55bc5212020-01-27 11:46:39 -0800137import java.util.stream.Collectors;
Janak Ramakrishnanb5a541a2015-06-19 20:55:01 +0000138
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000139/**
140 * {@link AbstractBlazeQueryEnvironment} that introspects the Skyframe graph to find forward and
Googlerd1911622016-06-27 15:43:11 +0000141 * reverse edges. Results obtained by calling {@link #evaluateQuery} are not guaranteed to be in any
142 * particular order. As well, this class eagerly loads the full transitive closure of targets, even
143 * if the full closure isn't needed.
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000144 *
janakrb8bc2842021-12-08 12:48:02 -0800145 * <p>This class has concurrent implementations of the {@link QueryTaskFuture}/{@link
146 * QueryTaskCallable} helper methods. The combination of this and the asynchronous evaluation model
147 * yields parallel query evaluation.
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000148 */
Googlerd1911622016-06-27 15:43:11 +0000149public class SkyQueryEnvironment extends AbstractBlazeQueryEnvironment<Target>
150 implements StreamableQueryEnvironment<Target> {
Janak Ramakrishnanae3a20a2016-01-08 16:24:29 +0000151 // 10k is likely a good balance between using batch efficiently and not blowing up memory.
152 // TODO(janakr): Unify with RecursivePackageProviderBackedTargetPatternResolver's constant.
nharmata1bd4aaf2017-10-31 11:23:04 -0400153 protected static final int BATCH_CALLBACK_SIZE = 10000;
gregcea91495f2019-05-07 07:27:39 -0700154 public static final int DEFAULT_THREAD_COUNT = Runtime.getRuntime().availableProcessors();
janakr0fa30222020-04-13 17:38:06 -0700155 private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
Mark Schallerd7311e02015-07-07 16:36:09 +0000156
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000157 private final BlazeTargetAccessor accessor = new BlazeTargetAccessor(this);
Janak Ramakrishnandf694322016-11-08 18:28:12 +0000158 protected final int loadingPhaseThreads;
159 protected final WalkableGraphFactory graphFactory;
nharmatae294b342020-07-16 17:56:21 -0700160 protected final UniverseScope universeScope;
Mark Schaller4f48f1b2017-03-10 20:38:43 +0000161 protected boolean blockUniverseEvaluationErrors;
162 protected ExtendedEventHandler universeEvalEventHandler;
janakra3652a32020-09-10 12:05:20 -0700163 protected final PathFragment parserPrefix;
Janak Ramakrishnandf694322016-11-08 18:28:12 +0000164 protected final PathPackageLocator pkgPath;
nharmatafac7c252018-09-12 15:31:23 -0700165 protected final int queryEvaluationParallelismLevel;
nharmata21aadcb2019-07-25 18:19:19 -0700166 private final boolean visibilityDepsAreAllowed;
Mark Schaller6cebed62016-06-27 18:05:39 +0000167
168 // The following fields are set in the #beforeEvaluateQuery method.
nharmatafbdd5932021-05-20 12:07:09 -0700169 protected MultisetSemaphore<PackageIdentifier> packageSemaphore;
Mark Schaller6cebed62016-06-27 18:05:39 +0000170 protected WalkableGraph graph;
kkress1847a012020-06-24 12:30:11 -0700171 protected InterruptibleSupplier<ImmutableSet<PathFragment>> ignoredPatternsSupplier;
Googleree343922019-03-05 08:51:12 -0800172 protected GraphBackedRecursivePackageProvider graphBackedRecursivePackageProvider;
173 protected ListeningExecutorService executor;
nharmatafbdd5932021-05-20 12:07:09 -0700174 private TargetPatternResolver<Target> resolver;
Miguel Alcon Pintob45e2622015-08-21 18:31:23 +0000175
Mark Schaller4b801f22016-06-21 22:26:12 +0000176 public SkyQueryEnvironment(
177 boolean keepGoing,
178 int loadingPhaseThreads,
Klaus Aehlig777b30d2017-02-24 16:30:15 +0000179 ExtendedEventHandler eventHandler,
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000180 Set<Setting> settings,
Mark Schaller20c75012016-06-21 22:51:14 +0000181 Iterable<QueryFunction> extraFunctions,
janakra3652a32020-09-10 12:05:20 -0700182 PathFragment parserPrefix,
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000183 WalkableGraphFactory graphFactory,
nharmatae294b342020-07-16 17:56:21 -0700184 UniverseScope universeScope,
Mark Schaller4f48f1b2017-03-10 20:38:43 +0000185 PathPackageLocator pkgPath,
186 boolean blockUniverseEvaluationErrors) {
Nathan Harmata2e2b4592016-09-21 17:17:33 +0000187 this(
188 keepGoing,
189 loadingPhaseThreads,
190 // SkyQueryEnvironment operates on a prepopulated Skyframe graph. Therefore, query
191 // evaluation is completely CPU-bound.
192 /*queryEvaluationParallelismLevel=*/ DEFAULT_THREAD_COUNT,
193 eventHandler,
194 settings,
195 extraFunctions,
Nathan Harmata2e2b4592016-09-21 17:17:33 +0000196 parserPrefix,
197 graphFactory,
198 universeScope,
Mark Schaller4f48f1b2017-03-10 20:38:43 +0000199 pkgPath,
200 blockUniverseEvaluationErrors);
Nathan Harmata2e2b4592016-09-21 17:17:33 +0000201 }
202
203 protected SkyQueryEnvironment(
204 boolean keepGoing,
205 int loadingPhaseThreads,
206 int queryEvaluationParallelismLevel,
Klaus Aehlig777b30d2017-02-24 16:30:15 +0000207 ExtendedEventHandler eventHandler,
Nathan Harmata2e2b4592016-09-21 17:17:33 +0000208 Set<Setting> settings,
209 Iterable<QueryFunction> extraFunctions,
janakra3652a32020-09-10 12:05:20 -0700210 PathFragment parserPrefix,
Nathan Harmata2e2b4592016-09-21 17:17:33 +0000211 WalkableGraphFactory graphFactory,
nharmatae294b342020-07-16 17:56:21 -0700212 UniverseScope universeScope,
Mark Schaller4f48f1b2017-03-10 20:38:43 +0000213 PathPackageLocator pkgPath,
214 boolean blockUniverseEvaluationErrors) {
Mark Schaller4b801f22016-06-21 22:26:12 +0000215 super(
216 keepGoing,
217 /*strictScope=*/ true,
218 /*labelFilter=*/ Rule.ALL_LABELS,
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000219 eventHandler,
220 settings,
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000221 extraFunctions);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000222 this.loadingPhaseThreads = loadingPhaseThreads;
223 this.graphFactory = graphFactory;
Mark Schallerb889cf32015-03-17 20:55:30 +0000224 this.pkgPath = pkgPath;
nharmatae294b342020-07-16 17:56:21 -0700225 this.universeScope = universeScope;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000226 this.parserPrefix = parserPrefix;
Nathan Harmata71616b12016-09-28 20:20:48 +0000227 this.queryEvaluationParallelismLevel = queryEvaluationParallelismLevel;
Mark Schaller4f48f1b2017-03-10 20:38:43 +0000228 this.blockUniverseEvaluationErrors = blockUniverseEvaluationErrors;
229 this.universeEvalEventHandler =
230 this.blockUniverseEvaluationErrors
231 ? new ErrorBlockingForwardingEventHandler(this.eventHandler)
232 : this.eventHandler;
nharmata21aadcb2019-07-25 18:19:19 -0700233 // In #getAllowedDeps we have special treatment of deps entailed by the `visibility` attribute.
234 // Since this attribute is of the NODEP type, that means we need a special implementation of
235 // NO_NODEP_DEPS.
236 this.visibilityDepsAreAllowed = !settings.contains(Setting.NO_NODEP_DEPS);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000237 }
238
mschallerfe883872017-07-17 22:40:11 +0200239 @Override
240 public void close() {
241 if (executor != null) {
242 executor.shutdownNow();
243 executor = null;
244 }
245 }
246
Googler5e65c982017-08-17 05:21:54 +0200247 /** Gets roots of graph which contains all nodes needed to evaluate {@code expr}. */
nharmatae294b342020-07-16 17:56:21 -0700248 protected Set<SkyKey> getGraphRootsFromUniverseKeyAndExpression(
249 SkyKey universeKey, QueryExpression expr) throws QueryException, InterruptedException {
Googler5e65c982017-08-17 05:21:54 +0200250 return ImmutableSet.of(universeKey);
251 }
252
nharmata102c2c12021-12-22 10:25:14 -0800253 protected EvaluationContext newEvaluationContext() {
254 return EvaluationContext.newBuilder()
255 .setNumThreads(loadingPhaseThreads)
256 .setEventHandler(universeEvalEventHandler)
257 .build();
258 }
259
nharmata6147ebf2018-10-09 08:43:49 -0700260 protected void beforeEvaluateQuery(QueryExpression expr)
Googler5e65c982017-08-17 05:21:54 +0200261 throws QueryException, InterruptedException {
janakra3652a32020-09-10 12:05:20 -0700262 UniverseSkyKey universeKey = universeScope.getUniverseKey(expr, parserPrefix);
263 ImmutableList<String> universeScopeListToUse = universeKey.getPatterns();
nharmatae294b342020-07-16 17:56:21 -0700264 logger.atInfo().log("Using a --universe_scope value of %s", universeScopeListToUse);
nharmatae294b342020-07-16 17:56:21 -0700265 Set<SkyKey> roots = getGraphRootsFromUniverseKeyAndExpression(universeKey, expr);
Googler5e65c982017-08-17 05:21:54 +0200266
Googler53755202018-02-13 11:37:30 -0800267 EvaluationResult<SkyValue> result;
janakr30e99152020-04-03 08:01:25 -0700268 try (AutoProfiler p = GoogleAutoProfilerUtils.logged("evaluation and walkable graph")) {
nharmata102c2c12021-12-22 10:25:14 -0800269 result = graphFactory.prepareAndGet(roots, newEvaluationContext());
Googler53755202018-02-13 11:37:30 -0800270 }
Googler57f228a2017-12-21 08:10:15 -0800271
Googler53755202018-02-13 11:37:30 -0800272 if (graph == null || graph != result.getWalkableGraph()) {
janakra01210f2022-02-17 18:56:01 -0800273 checkEvaluationResult(universeScopeListToUse, roots, universeKey, result, expr);
Janak Ramakrishnan3207f932016-11-16 23:16:53 +0000274 packageSemaphore = makeFreshPackageMultisetSemaphore();
janakrb8bc2842021-12-08 12:48:02 -0800275 graph = Preconditions.checkNotNull(result.getWalkableGraph(), result);
kkress1847a012020-06-24 12:30:11 -0700276 ignoredPatternsSupplier =
277 MemoizingInterruptibleSupplier.of(new IgnoredPatternSupplier(graph));
Janak Ramakrishnan3207f932016-11-16 23:16:53 +0000278 graphBackedRecursivePackageProvider =
juliexxiacc864752018-06-01 09:03:48 -0700279 new GraphBackedRecursivePackageProvider(
nharmata697d2192019-08-22 11:03:18 -0700280 graph,
John Cater97aebaa2021-04-12 06:10:00 -0700281 UniverseTargetPattern.of(getTargetPatternsForUniverseKey(universeKey)),
nharmata697d2192019-08-22 11:03:18 -0700282 pkgPath,
283 new TraversalInfoRootPackageExtractor());
Eric Fellheimera39f8a92015-07-28 19:11:23 +0000284 }
Googler57f228a2017-12-21 08:10:15 -0800285
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000286 if (executor == null) {
janakrb8bc2842021-12-08 12:48:02 -0800287 executor =
288 MoreExecutors.listeningDecorator(
289 new ThreadPoolExecutor(
290 /*corePoolSize=*/ queryEvaluationParallelismLevel,
291 /*maximumPoolSize=*/ queryEvaluationParallelismLevel,
292 /*keepAliveTime=*/ 1,
293 /*unit=*/ TimeUnit.SECONDS,
294 /*workQueue=*/ new BlockingStack<Runnable>(),
295 new ThreadFactoryBuilder().setNameFormat("QueryEnvironment %d").build()));
Janak Ramakrishnan3207f932016-11-16 23:16:53 +0000296 }
nharmatafbdd5932021-05-20 12:07:09 -0700297 resolver = makeNewTargetPatternResolver();
298 }
299
300 protected TargetPatternResolver<Target> makeNewTargetPatternResolver() {
301 return new RecursivePackageProviderBackedTargetPatternResolver(
302 graphBackedRecursivePackageProvider,
303 eventHandler,
304 FilteringPolicies.NO_FILTER,
305 packageSemaphore,
306 SimplePackageIdentifierBatchingCallback::new);
Nathan Harmata41b54172016-11-10 18:54:09 +0000307 }
308
nharmatae294b342020-07-16 17:56:21 -0700309 /** Returns the TargetPatterns corresponding to {@code universeKey}. */
310 protected ImmutableList<TargetPattern> getTargetPatternsForUniverseKey(SkyKey universeKey) {
nharmata697d2192019-08-22 11:03:18 -0700311 return ImmutableList.copyOf(
312 Iterables.transform(
313 PrepareDepsOfPatternsFunction.getTargetPatternKeys(
314 PrepareDepsOfPatternsFunction.getSkyKeys(universeKey, eventHandler)),
315 TargetPatternKey::getParsedPattern));
316 }
317
Nathan Harmata41b54172016-11-10 18:54:09 +0000318 protected MultisetSemaphore<PackageIdentifier> makeFreshPackageMultisetSemaphore() {
319 return MultisetSemaphore.unbounded();
320 }
321
322 @ThreadSafe
323 public MultisetSemaphore<PackageIdentifier> getPackageMultisetSemaphore() {
324 return packageSemaphore;
Mark Schaller6cebed62016-06-27 18:05:39 +0000325 }
Janak Ramakrishnan958ef822016-01-07 16:21:39 +0000326
nharmata76d5fd02019-08-30 12:44:34 -0700327 boolean hasDependencyFilter() {
328 return dependencyFilter != DependencyFilter.ALL_DEPS;
329 }
330
janakrb8bc2842021-12-08 12:48:02 -0800331 private void checkEvaluationResult(
nharmatae294b342020-07-16 17:56:21 -0700332 ImmutableList<String> universeScopeList,
333 Set<SkyKey> roots,
334 SkyKey universeKey,
janakra01210f2022-02-17 18:56:01 -0800335 EvaluationResult<SkyValue> result,
336 QueryExpression exprForError)
Googler61c48b52017-10-30 17:33:04 -0400337 throws QueryException {
338 // If the only root is the universe key, we expect to see either a single successfully evaluated
janakrb8bc2842021-12-08 12:48:02 -0800339 // value or a cycle in the result or a catastrophic error.
340 Collection<SkyValue> values = result.values();
341 if (!values.isEmpty()) {
342 if (roots.size() != 1 || !Iterables.getOnlyElement(roots).equals(universeKey)) {
343 return;
344 }
345 Preconditions.checkState(
346 values.size() == 1,
347 "Universe query \"%s\" returned multiple values unexpectedly (%s values in result)",
348 universeScopeList,
349 values.size());
350 Preconditions.checkNotNull(result.get(universeKey), result);
351 return;
352 }
353 Preconditions.checkState(
354 result.hasError(),
355 "Universe query \"%s\" failed but had no error: %s",
356 universeScopeList,
357 result);
janakra01210f2022-02-17 18:56:01 -0800358 QueryTransitivePackagePreloader.maybeThrowQueryExceptionForResultWithError(
359 result, roots, exprForError, /*operation=*/ "Building universe scope");
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000360 }
361
janakr30e99152020-04-03 08:01:25 -0700362 private static final Duration MIN_LOGGING = Duration.ofMillis(50);
363
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000364 @Override
Nathan Harmata2643c8e2016-07-01 23:19:23 +0000365 public final QueryExpression transformParsedQuery(QueryExpression queryExpression) {
nharmata327b9112018-01-31 10:48:31 -0800366 QueryExpressionMapper<Void> mapper = getQueryExpressionMapper();
adgard1e1cb72019-05-14 08:32:51 -0700367 QueryExpression transformedQueryExpression;
janakr30e99152020-04-03 08:01:25 -0700368 try (AutoProfiler p = GoogleAutoProfilerUtils.logged("transforming query", MIN_LOGGING)) {
adgard1e1cb72019-05-14 08:32:51 -0700369 transformedQueryExpression = queryExpression.accept(mapper);
370 }
janakr0fa30222020-04-13 17:38:06 -0700371 logger.atInfo().log(
372 "transformed query [%s] to [%s]",
mschaller2e1480d2020-09-16 10:54:04 -0700373 queryExpression.toTrunctatedString(), transformedQueryExpression.toTrunctatedString());
Nathan Harmataed935602016-03-02 01:16:14 +0000374 return transformedQueryExpression;
375 }
376
nharmata327b9112018-01-31 10:48:31 -0800377 protected QueryExpressionMapper<Void> getQueryExpressionMapper() {
nharmatae294b342020-07-16 17:56:21 -0700378 Optional<ImmutableList<String>> constantUniverseScopeListMaybe =
379 universeScope.getConstantValueMaybe();
380 if (!constantUniverseScopeListMaybe.isPresent()) {
381 return QueryExpressionMapper.identity();
382 }
383 ImmutableList<String> constantUniverseScopeList = constantUniverseScopeListMaybe.get();
384 if (constantUniverseScopeList.size() != 1) {
Nathan Harmata54a16f02016-12-13 17:49:27 +0000385 return QueryExpressionMapper.identity();
Nathan Harmata64543472016-06-30 18:33:40 +0000386 }
wyv630be022021-10-04 07:55:36 -0700387 TargetPattern.Parser targetPatternParser = TargetPattern.mainRepoParser(parserPrefix);
nharmata63c8a222021-03-08 13:18:33 -0800388 String universeScopePatternString = Iterables.getOnlyElement(constantUniverseScopeList);
389 TargetPattern absoluteUniverseScopePattern = null;
390 try {
391 absoluteUniverseScopePattern =
392 targetPatternParser.parse(targetPatternParser.absolutize(universeScopePatternString));
393 } catch (TargetParsingException e) {
394 return QueryExpressionMapper.identity();
395 }
adgarbed158e2019-07-30 12:40:32 -0700396 return QueryExpressionMapper.compose(
michajlo7a079c42019-08-22 09:24:28 -0700397 ImmutableList.of(
nharmata63c8a222021-03-08 13:18:33 -0800398 new RdepsToAllRdepsQueryExpressionMapper(
399 targetPatternParser, absoluteUniverseScopePattern),
michajlo7a079c42019-08-22 09:24:28 -0700400 new FilteredDirectRdepsInUniverseExpressionMapper(
nharmata63c8a222021-03-08 13:18:33 -0800401 targetPatternParser, absoluteUniverseScopePattern)));
Nathan Harmata64543472016-06-30 18:33:40 +0000402 }
403
Nathan Harmataed935602016-03-02 01:16:14 +0000404 @Override
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000405 protected void evalTopLevelInternal(
406 QueryExpression expr, OutputFormatterCallback<Target> callback)
janakrb8bc2842021-12-08 12:48:02 -0800407 throws QueryException, InterruptedException {
Nathan Harmata79e49652016-12-16 22:00:48 +0000408 Throwable throwableToThrow = null;
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000409 try {
410 super.evalTopLevelInternal(expr, callback);
Nathan Harmata79e49652016-12-16 22:00:48 +0000411 } catch (Throwable throwable) {
412 throwableToThrow = throwable;
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000413 } finally {
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000414 if (throwableToThrow != null) {
janakr0fa30222020-04-13 17:38:06 -0700415 logger.atInfo().withCause(throwableToThrow).log(
416 "About to shutdown query threadpool because of throwable");
mschaller6d155d72018-08-28 15:12:34 -0700417 ListeningExecutorService obsoleteExecutor = executor;
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000418 // Signal that executor must be recreated on the next invocation.
419 executor = null;
mschaller6d155d72018-08-28 15:12:34 -0700420
421 // If evaluation failed abruptly (e.g. was interrupted), attempt to terminate all remaining
422 // tasks and then wait for them all to finish. We don't want to leave any dangling threads
423 // running tasks.
424 obsoleteExecutor.shutdownNow();
425 boolean interrupted = false;
426 boolean executorTerminated = false;
427 try {
428 while (!executorTerminated) {
429 try {
430 executorTerminated =
431 obsoleteExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
432 } catch (InterruptedException e) {
433 interrupted = true;
434 handleInterruptedShutdown();
435 }
436 }
437 } finally {
438 if (interrupted) {
439 Thread.currentThread().interrupt();
440 }
441 }
442
Nathan Harmata79e49652016-12-16 22:00:48 +0000443 Throwables.propagateIfPossible(
444 throwableToThrow, QueryException.class, InterruptedException.class);
Janak Ramakrishnan3207f932016-11-16 23:16:53 +0000445 }
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000446 }
447 }
448
mschaller6d155d72018-08-28 15:12:34 -0700449 /**
450 * Subclasses may implement special handling when the query threadpool shutdown process is
451 * interrupted. This isn't likely to happen unless there's a bug in the lifecycle management of
452 * query tasks.
453 */
454 protected void handleInterruptedShutdown() {}
455
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000456 @Override
457 public QueryEvalResult evaluateQuery(
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000458 QueryExpression expr, ThreadSafeOutputFormatterCallback<Target> callback)
janakrb8bc2842021-12-08 12:48:02 -0800459 throws QueryException, InterruptedException, IOException {
Googler5e65c982017-08-17 05:21:54 +0200460 beforeEvaluateQuery(expr);
Mark Schaller4d8baf82016-06-21 18:56:04 +0000461
462 // SkyQueryEnvironment batches callback invocations using a BatchStreamedCallback, created here
463 // so that there's one per top-level evaluateQuery call. The batch size is large enough that
464 // per-call costs of calling the original callback are amortized over a good number of targets,
465 // and small enough that holding a batch of targets in memory doesn't risk an OOM error.
466 //
467 // This flushes the batched callback prior to constructing the QueryEvalResult in the unlikely
468 // case of a race between the original callback and the eventHandler.
janakrb8bc2842021-12-08 12:48:02 -0800469 BatchStreamedCallback batchCallback =
470 new BatchStreamedCallback(
471 callback, BATCH_CALLBACK_SIZE, createUniquifierForOuterBatchStreamedCallback(expr));
janakrfb744c82022-01-20 15:57:35 -0800472 return evaluateQueryInternal(expr, batchCallback);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000473 }
474
shreyax6bebe382019-11-13 06:26:26 -0800475 Map<SkyKey, Collection<Target>> targetifyValues(Map<SkyKey, ? extends Iterable<SkyKey>> input)
476 throws InterruptedException {
Nathan Harmata41b54172016-11-10 18:54:09 +0000477 return targetifyValues(
janakrb8bc2842021-12-08 12:48:02 -0800478 input, makePackageKeyToTargetKeyMap(ImmutableSet.copyOf(Iterables.concat(input.values()))));
Nathan Harmata41b54172016-11-10 18:54:09 +0000479 }
480
481 private Map<SkyKey, Collection<Target>> targetifyValues(
482 Map<SkyKey, ? extends Iterable<SkyKey>> input,
janakrb8bc2842021-12-08 12:48:02 -0800483 Multimap<SkyKey, SkyKey> packageKeyToTargetKeyMap)
484 throws InterruptedException {
Nathan Harmatabe597992016-10-10 15:59:00 +0000485 ImmutableMap.Builder<SkyKey, Collection<Target>> result = ImmutableMap.builder();
Googlerd1911622016-06-27 15:43:11 +0000486
Janak Ramakrishnane933d5e2016-01-08 16:43:54 +0000487 Map<SkyKey, Target> allTargets =
nharmata7c56dce2018-08-16 10:50:26 -0700488 getTargetKeyToTargetMapForPackageKeyToTargetKeyMap(packageKeyToTargetKeyMap);
Janak Ramakrishnan36858732015-06-17 16:45:47 +0000489
Googlerb3610d52016-10-24 19:18:36 +0000490 for (Map.Entry<SkyKey, ? extends Iterable<SkyKey>> entry : input.entrySet()) {
Nathan Harmatabe597992016-10-10 15:59:00 +0000491 Iterable<SkyKey> skyKeys = entry.getValue();
Miguel Alcon Pinto933c13a2015-09-16 18:37:45 +0000492 Set<Target> targets = CompactHashSet.createWithExpectedSize(Iterables.size(skyKeys));
493 for (SkyKey key : skyKeys) {
494 Target target = allTargets.get(key);
495 if (target != null) {
496 targets.add(target);
497 }
498 }
Nathan Harmatabe597992016-10-10 15:59:00 +0000499 result.put(entry.getKey(), targets);
Janak Ramakrishnan36858732015-06-17 16:45:47 +0000500 }
Googler2fc3d3f2022-02-01 06:29:56 -0800501 return result.buildOrThrow();
Janak Ramakrishnan36858732015-06-17 16:45:47 +0000502 }
503
Nathan Harmatabe597992016-10-10 15:59:00 +0000504 private Map<SkyKey, Collection<Target>> getRawReverseDeps(
505 Iterable<SkyKey> transitiveTraversalKeys) throws InterruptedException {
shreyax5e69f082020-01-07 10:15:37 -0800506 return targetifyValues(getReverseDepLabelsOfLabels(transitiveTraversalKeys));
507 }
508
shreyaxf17441ad2020-01-07 14:15:14 -0800509 protected Map<SkyKey, Iterable<SkyKey>> getReverseDepLabelsOfLabels(
510 Iterable<? extends SkyKey> labels) throws InterruptedException {
shreyax5e69f082020-01-07 10:15:37 -0800511 return graph.getReverseDeps(labels);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000512 }
513
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000514 private Set<Label> getAllowedDeps(Rule rule) throws InterruptedException {
Miguel Alcon Pinto4ffe28d2015-08-19 14:29:02 +0000515 Set<Label> allowedLabels = new HashSet<>(rule.getTransitions(dependencyFilter).values());
nharmata21aadcb2019-07-25 18:19:19 -0700516 if (visibilityDepsAreAllowed) {
517 // Rule#getTransitions only visits the labels of attribute values, so that means it doesn't
518 // know about deps from the labels of the rule's package's default_visibility. Therefore, we
519 // need to explicitly handle that here.
520 allowedLabels.addAll(rule.getVisibility().getDependencyLabels());
521 }
Marian Loburfdd788e2015-03-25 09:36:28 +0000522 // We should add deps from aspects, otherwise they are going to be filtered out.
523 allowedLabels.addAll(rule.getAspectLabelsSuperset(dependencyFilter));
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000524 return allowedLabels;
525 }
526
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000527 private Collection<Target> filterFwdDeps(Target target, Collection<Target> rawFwdDeps)
528 throws InterruptedException {
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000529 if (!(target instanceof Rule)) {
Janak Ramakrishnan36858732015-06-17 16:45:47 +0000530 return rawFwdDeps;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000531 }
jhorvitzdd1d8412020-08-01 05:59:14 -0700532 Set<Label> allowedLabels = getAllowedDeps((Rule) target);
533 return Collections2.filter(rawFwdDeps, t -> allowedLabels.contains(t.getLabel()));
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000534 }
535
nharmatabf2e2d82017-06-21 23:12:51 +0200536 @Override
shreyax159a6112018-06-12 15:34:09 -0700537 public ThreadSafeMutableSet<Target> getFwdDeps(
538 Iterable<Target> targets, QueryExpressionContext<Target> context)
nharmatabf2e2d82017-06-21 23:12:51 +0200539 throws InterruptedException {
nharmata523b5752017-08-10 21:00:52 +0200540 Map<SkyKey, Target> targetsByKey = Maps.newHashMapWithExpectedSize(Iterables.size(targets));
nharmatabf2e2d82017-06-21 23:12:51 +0200541 for (Target target : targets) {
542 targetsByKey.put(TARGET_TO_SKY_KEY.apply(target), target);
543 }
shreyax6bebe382019-11-13 06:26:26 -0800544 Map<SkyKey, Collection<Target>> directDeps =
545 targetifyValues(getFwdDepLabels(targetsByKey.keySet()));
nharmatabf2e2d82017-06-21 23:12:51 +0200546 if (targetsByKey.keySet().size() != directDeps.keySet().size()) {
shreyax6bebe382019-11-13 06:26:26 -0800547 Iterable<SkyKey> missingTargets = Sets.difference(targetsByKey.keySet(), directDeps.keySet());
Janak Ramakrishnan3533ab52016-01-14 18:14:09 +0000548 eventHandler.handle(Event.warn("Targets were missing from graph: " + missingTargets));
549 }
nharmatabf2e2d82017-06-21 23:12:51 +0200550 ThreadSafeMutableSet<Target> result = createThreadSafeMutableSet();
551 for (Map.Entry<SkyKey, Collection<Target>> entry : directDeps.entrySet()) {
552 result.addAll(filterFwdDeps(targetsByKey.get(entry.getKey()), entry.getValue()));
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000553 }
554 return result;
555 }
556
shreyax6bebe382019-11-13 06:26:26 -0800557 /** Returns the target dependencies' {@link Label}s of the passed in target {@code Label}s. */
558 protected Map<SkyKey, Iterable<SkyKey>> getFwdDepLabels(Iterable<SkyKey> targetLabels)
nharmata398e6dab2018-04-12 15:31:26 -0700559 throws InterruptedException {
shreyax6bebe382019-11-13 06:26:26 -0800560 Preconditions.checkState(
561 Iterables.all(targetLabels, IS_LABEL), "Expected all labels: %s", targetLabels);
562 return graph.getDirectDeps(targetLabels).entrySet().stream()
563 .collect(
564 ImmutableMap.toImmutableMap(
565 Map.Entry::getKey, entry -> Iterables.filter(entry.getValue(), IS_LABEL)));
nharmata398e6dab2018-04-12 15:31:26 -0700566 }
567
Janak Ramakrishnan36858732015-06-17 16:45:47 +0000568 @Override
shreyax55bc5212020-01-27 11:46:39 -0800569 public QueryTaskFuture<Void> getDepsBounded(
570 QueryExpression queryExpression,
571 QueryExpressionContext<Target> context,
572 Callback<Target> callback,
573 int depthBound,
574 QueryExpression caller) {
575 // Re-implement the bounded deps algorithm to allow for proper error reporting of missing
576 // targets that cannot be targetified.
577 final MinDepthUniquifier<Target> minDepthUniquifier = createMinDepthUniquifier();
578 return eval(
579 queryExpression,
580 context,
581 partialResult -> {
582 ThreadSafeMutableSet<Target> current = createThreadSafeMutableSet();
583 Iterables.addAll(current, partialResult);
584
585 for (int i = 0; i <= depthBound; i++) {
586 // Filter already visited nodes: if we see a node in a later round, then we don't need
587 // to visit it again, because the depth at which we see it at must be greater than or
588 // equal to the last visit.
589 ImmutableList<Target> toProcess =
590 minDepthUniquifier.uniqueAtDepthLessThanOrEqualTo(current, i);
591 callback.process(toProcess);
592
593 if (i == depthBound) {
594 // We don't need to fetch dep targets any more.
595 break;
596 }
597
598 current = createThreadSafeMutableSet();
599 addTargetsOfDirectDepsAndReportErrorsIfAny(context, caller, current, toProcess);
600
601 if (current.isEmpty()) {
602 // Exit when there are no more nodes to visit.
603 break;
604 }
605 }
606 });
607 }
608
609 protected void addTargetsOfDirectDepsAndReportErrorsIfAny(
610 QueryExpressionContext<Target> context,
611 QueryExpression caller,
612 ThreadSafeMutableSet<Target> toAddTo,
613 ImmutableList<Target> toProcess)
614 throws InterruptedException, QueryException {
615 Map<SkyKey, Iterable<SkyKey>> keyToDepKeys =
616 getFwdDepLabels(toProcess.stream().map(Target::getLabel).collect(Collectors.toList()));
617 Map<SkyKey, Collection<Target>> targetDepMap = targetifyValues(keyToDepKeys);
618
619 Map<SkyKey, Target> targetMap = new HashMap<>();
620 Set<SkyKey> depLabels = ImmutableSet.copyOf(Iterables.concat(keyToDepKeys.values()));
shreyax6c0ec482020-01-27 12:33:58 -0800621 for (Collection<Target> depTargets : targetDepMap.values()) {
622 for (Target depTarget : depTargets) {
623 targetMap.putIfAbsent(depTarget.getLabel(), depTarget);
624 toAddTo.add(depTarget);
shreyax55bc5212020-01-27 11:46:39 -0800625 }
626 }
627 reportUnsuccessfulOrMissingTargets(targetMap, depLabels, caller);
628 }
629
630 @Override
shreyax159a6112018-06-12 15:34:09 -0700631 public Collection<Target> getReverseDeps(
632 Iterable<Target> targets, QueryExpressionContext<Target> context)
633 throws InterruptedException {
shreyax5e69f082020-01-07 10:15:37 -0800634 return processRawReverseDeps(
shreyaxa7ade6f2021-04-26 06:35:11 -0700635 getReverseDepsOfLabels(Iterables.transform(targets, Target::getLabel), context));
Nathan Harmatabe597992016-10-10 15:59:00 +0000636 }
Miguel Alcon Pintob45e2622015-08-21 18:31:23 +0000637
shreyaxa7ade6f2021-04-26 06:35:11 -0700638 protected Map<SkyKey, Collection<Target>> getReverseDepsOfLabels(
639 Iterable<Label> targetLabels, QueryExpressionContext<Target> context)
shreyax6bebe382019-11-13 06:26:26 -0800640 throws InterruptedException {
shreyax5e69f082020-01-07 10:15:37 -0800641 return getRawReverseDeps(Iterables.transform(targetLabels, label -> label));
Googlerd1911622016-06-27 15:43:11 +0000642 }
643
Googlerb3610d52016-10-24 19:18:36 +0000644 /** Targetify SkyKeys of reverse deps and filter out targets whose deps are not allowed. */
645 Collection<Target> filterRawReverseDepsOfTransitiveTraversalKeys(
Nathan Harmata41b54172016-11-10 18:54:09 +0000646 Map<SkyKey, ? extends Iterable<SkyKey>> rawReverseDeps,
janakrb8bc2842021-12-08 12:48:02 -0800647 Multimap<SkyKey, SkyKey> packageKeyToTargetKeyMap)
648 throws InterruptedException {
Nathan Harmata41b54172016-11-10 18:54:09 +0000649 return processRawReverseDeps(targetifyValues(rawReverseDeps, packageKeyToTargetKeyMap));
Googlerb3610d52016-10-24 19:18:36 +0000650 }
651
Nathan Harmatabe597992016-10-10 15:59:00 +0000652 private Collection<Target> processRawReverseDeps(Map<SkyKey, Collection<Target>> rawReverseDeps)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000653 throws InterruptedException {
Googlerd1911622016-06-27 15:43:11 +0000654 Set<Target> result = CompactHashSet.create();
Eric Fellheimercfd61cf2016-08-10 21:36:02 +0000655 CompactHashSet<Target> visited =
656 CompactHashSet.createWithExpectedSize(totalSizeOfCollections(rawReverseDeps.values()));
Miguel Alcon Pintob45e2622015-08-21 18:31:23 +0000657
janakrb8bc2842021-12-08 12:48:02 -0800658 Set<Label> keys =
659 CompactHashSet.create(Collections2.transform(rawReverseDeps.keySet(), SKYKEY_TO_LABEL));
Miguel Alcon Pintob45e2622015-08-21 18:31:23 +0000660 for (Collection<Target> parentCollection : rawReverseDeps.values()) {
661 for (Target parent : parentCollection) {
662 if (visited.add(parent)) {
Dmitry Lomov6073eb62016-01-21 21:26:32 +0000663 if (parent instanceof Rule && dependencyFilter != DependencyFilter.ALL_DEPS) {
Miguel Alcon Pintob45e2622015-08-21 18:31:23 +0000664 for (Label label : getAllowedDeps((Rule) parent)) {
665 if (keys.contains(label)) {
666 result.add(parent);
667 }
668 }
669 } else {
670 result.add(parent);
671 }
672 }
673 }
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000674 }
675 return result;
676 }
677
Eric Fellheimercfd61cf2016-08-10 21:36:02 +0000678 private static <T> int totalSizeOfCollections(Iterable<Collection<T>> nestedCollections) {
679 int totalSize = 0;
680 for (Collection<T> collection : nestedCollections) {
681 totalSize += collection.size();
682 }
683 return totalSize;
684 }
685
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000686 @Override
shreyax159a6112018-06-12 15:34:09 -0700687 public ThreadSafeMutableSet<Target> getTransitiveClosure(
688 ThreadSafeMutableSet<Target> targets, QueryExpressionContext<Target> context)
nharmatabf2e2d82017-06-21 23:12:51 +0200689 throws InterruptedException {
janakrdc8b2e9a2017-08-18 22:52:37 +0200690 return SkyQueryUtils.getTransitiveClosure(
shreyax159a6112018-06-12 15:34:09 -0700691 targets, targets1 -> getFwdDeps(targets1, context), createThreadSafeMutableSet());
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000692 }
693
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000694 @Override
shreyax159a6112018-06-12 15:34:09 -0700695 public ImmutableList<Target> getNodesOnPath(
696 Target from, Target to, QueryExpressionContext<Target> context) throws InterruptedException {
697 return SkyQueryUtils.getNodesOnPath(
698 from, to, targets -> getFwdDeps(targets, context), Target::getLabel);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000699 }
700
Googlerb39486c2019-01-03 08:58:16 -0800701 protected final <R> ListenableFuture<R> safeSubmit(Callable<R> callable) {
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000702 try {
703 return executor.submit(callable);
704 } catch (RejectedExecutionException e) {
705 return Futures.immediateCancelledFuture();
Nathan Harmataf37750a2016-09-07 14:58:14 +0000706 }
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +0000707 }
708
nharmata2ef8de62019-04-23 18:30:55 -0700709 @SuppressWarnings("unchecked")
710 private <R> ListenableFuture<R> safeSubmitAsync(QueryTaskAsyncCallable<R> callable) {
Googlerdb6e13b2017-10-19 17:26:59 +0200711 try {
nharmata2ef8de62019-04-23 18:30:55 -0700712 return Futures.submitAsync(() -> (ListenableFuture<R>) callable.call(), executor);
Googlerdb6e13b2017-10-19 17:26:59 +0200713 } catch (RejectedExecutionException e) {
714 return Futures.immediateCancelledFuture();
715 }
716 }
717
Nathan Harmataf37750a2016-09-07 14:58:14 +0000718 @ThreadSafe
Janak Ramakrishnane933d5e2016-01-08 16:43:54 +0000719 @Override
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000720 public QueryTaskFuture<Void> eval(
721 final QueryExpression expr,
shreyax159a6112018-06-12 15:34:09 -0700722 final QueryExpressionContext<Target> context,
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000723 final Callback<Target> callback) {
724 // TODO(bazel-team): As in here, use concurrency for the async #eval of other QueryEnvironment
725 // implementations.
nharmata2ef8de62019-04-23 18:30:55 -0700726 return executeAsync(() -> expr.eval(SkyQueryEnvironment.this, context, callback));
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000727 }
728
729 @Override
nharmata2ef8de62019-04-23 18:30:55 -0700730 public <R> QueryTaskFuture<R> execute(QueryTaskCallable<R> callable) {
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000731 return QueryTaskFutureImpl.ofDelegate(safeSubmit(callable));
732 }
733
734 @Override
nharmata2ef8de62019-04-23 18:30:55 -0700735 public <R> QueryTaskFuture<R> executeAsync(QueryTaskAsyncCallable<R> callable) {
736 return QueryTaskFutureImpl.ofDelegate(safeSubmitAsync(callable));
737 }
738
739 @Override
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000740 public <T1, T2> QueryTaskFuture<T2> transformAsync(
jhorvitzdd1d8412020-08-01 05:59:14 -0700741 QueryTaskFuture<T1> future, Function<T1, QueryTaskFuture<T2>> function) {
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000742 return QueryTaskFutureImpl.ofDelegate(
743 Futures.transformAsync(
744 (QueryTaskFutureImpl<T1>) future,
laurentlb3d2a68c2017-06-30 00:32:04 +0200745 input -> (QueryTaskFutureImpl<T2>) function.apply(input),
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000746 executor));
747 }
748
749 @Override
750 public <R> QueryTaskFuture<R> whenAllSucceedCall(
751 Iterable<? extends QueryTaskFuture<?>> futures, QueryTaskCallable<R> callable) {
752 return QueryTaskFutureImpl.ofDelegate(
753 Futures.whenAllSucceed(cast(futures)).call(callable, executor));
754 }
755
756 @ThreadSafe
757 @Override
nharmatabf2e2d82017-06-21 23:12:51 +0200758 public ThreadSafeMutableSet<Target> createThreadSafeMutableSet() {
759 return new ThreadSafeMutableKeyExtractorBackedSetImpl<>(
nharmatafac7c252018-09-12 15:31:23 -0700760 TargetKeyExtractor.INSTANCE, Target.class, queryEvaluationParallelismLevel);
nharmatabf2e2d82017-06-21 23:12:51 +0200761 }
762
763 @Override
764 public <V> MutableMap<Target, V> createMutableMap() {
shreyax6871cf02018-07-02 09:16:18 -0700765 return new MutableKeyExtractorBackedMapImpl<>(TargetKeyExtractor.INSTANCE);
nharmatabf2e2d82017-06-21 23:12:51 +0200766 }
767
768 @ThreadSafe
nharmatac49e8742018-09-27 11:27:41 -0700769 protected NonExceptionalUniquifier<Target> createUniquifierForOuterBatchStreamedCallback(
770 QueryExpression expr) {
771 return createUniquifier();
772 }
773
774 @ThreadSafe
nharmatabf2e2d82017-06-21 23:12:51 +0200775 @Override
nharmatac49e8742018-09-27 11:27:41 -0700776 public NonExceptionalUniquifier<Target> createUniquifier() {
nharmatab9f08022019-04-23 20:36:10 -0700777 return new UniquifierImpl<>(TargetKeyExtractor.INSTANCE, queryEvaluationParallelismLevel);
Nathan Harmata593dc522016-09-28 23:35:46 +0000778 }
779
780 @ThreadSafe
Nathan Harmatae9826b42017-03-07 18:05:21 +0000781 @Override
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000782 public MinDepthUniquifier<Target> createMinDepthUniquifier() {
nharmatafac7c252018-09-12 15:31:23 -0700783 return new MinDepthUniquifierImpl<>(
784 TargetKeyExtractor.INSTANCE, queryEvaluationParallelismLevel);
Nathan Harmatae9826b42017-03-07 18:05:21 +0000785 }
786
787 @ThreadSafe
nharmatafac7c252018-09-12 15:31:23 -0700788 public MinDepthUniquifier<SkyKey> createMinDepthSkyKeyUniquifier() {
789 return new MinDepthUniquifierImpl<>(
790 SkyKeyKeyExtractor.INSTANCE, queryEvaluationParallelismLevel);
nharmata398e6dab2018-04-12 15:31:26 -0700791 }
792
793 @ThreadSafe
shreyax2643d4b2018-05-25 11:12:11 -0700794 public Uniquifier<SkyKey> createSkyKeyUniquifier() {
nharmatab9f08022019-04-23 20:36:10 -0700795 return new UniquifierImpl<>(SkyKeyKeyExtractor.INSTANCE, queryEvaluationParallelismLevel);
Nathan Harmata593dc522016-09-28 23:35:46 +0000796 }
797
Googlerb3610d52016-10-24 19:18:36 +0000798 @ThreadSafe
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +0000799 @Override
nharmata50f72492017-08-11 21:31:03 +0200800 public Collection<Target> getSiblingTargetsInPackage(Target target) {
801 return target.getPackage().getTargets().values();
802 }
803
804 @ThreadSafe
805 @Override
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000806 public QueryTaskFuture<Void> getTargetsMatchingPattern(
nharmatade0c5352017-07-25 17:39:09 +0200807 QueryExpression owner, String pattern, Callback<Target> callback) {
808 TargetPatternKey targetPatternKey;
Mark Schaller77612fd2016-06-21 21:04:45 +0000809 try {
wyv630be022021-10-04 07:55:36 -0700810 targetPatternKey =
811 TargetPatternValue.key(
812 SignedTargetPattern.parse(pattern, TargetPattern.mainRepoParser(parserPrefix)),
813 FilteringPolicies.NO_FILTER);
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000814 } catch (TargetParsingException tpe) {
815 try {
mschaller0f61b362020-08-24 12:59:55 -0700816 handleError(owner, tpe.getMessage(), tpe.getDetailedExitCode());
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000817 } catch (QueryException qe) {
818 return immediateFailedFuture(qe);
819 }
820 return immediateSuccessfulFuture(null);
nharmatade0c5352017-07-25 17:39:09 +0200821 }
822 return evalTargetPatternKey(owner, targetPatternKey, callback);
823 }
824
825 @ThreadSafe
826 public QueryTaskFuture<Void> evalTargetPatternKey(
827 QueryExpression owner, TargetPatternKey targetPatternKey, Callback<Target> callback) {
nharmatade0c5352017-07-25 17:39:09 +0200828 TargetPattern patternToEval = targetPatternKey.getParsedPattern();
shreyax432b2532019-01-23 11:16:07 -0800829 Callback<Target> filteredCallback = callback;
830 if (!targetPatternKey.getPolicy().equals(NO_FILTER)) {
831 filteredCallback =
832 targets ->
833 callback.process(
834 Iterables.filter(
835 targets,
836 target ->
837 targetPatternKey.getPolicy().shouldRetain(target, /*explicit=*/ false)));
838 }
839 ListenableFuture<Void> evalFuture =
840 patternToEval.evalAsync(
841 resolver,
janakr3c38c412021-01-21 08:49:01 -0800842 ignoredPatternsSupplier,
843 targetPatternKey.getExcludedSubdirectories(),
shreyax432b2532019-01-23 11:16:07 -0800844 filteredCallback,
845 QueryException.class,
846 executor);
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000847 return QueryTaskFutureImpl.ofDelegate(
848 Futures.catchingAsync(
849 evalFuture,
850 TargetParsingException.class,
janakrb8bc2842021-12-08 12:48:02 -0800851 exn -> {
852 handleError(owner, exn.getMessage(), exn.getDetailedExitCode());
853 return immediateVoidFuture();
854 },
Googler73b7b2e2017-03-23 17:20:58 +0000855 directExecutor()));
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000856 }
857
Nathan Harmataf37750a2016-09-07 14:58:14 +0000858 @ThreadSafe
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000859 @Override
nharmatabf2e2d82017-06-21 23:12:51 +0200860 public ThreadSafeMutableSet<Target> getBuildFiles(
shreyax159a6112018-06-12 15:34:09 -0700861 QueryExpression caller,
862 ThreadSafeMutableSet<Target> nodes,
863 boolean buildFiles,
864 boolean loads,
865 QueryExpressionContext<Target> context)
shreyaxdac4d512018-05-02 16:26:13 -0700866 throws QueryException, InterruptedException {
nharmatabf2e2d82017-06-21 23:12:51 +0200867 ThreadSafeMutableSet<Target> dependentFiles = createThreadSafeMutableSet();
868 Set<PackageIdentifier> seenPackages = new HashSet<>();
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000869 // Keep track of seen labels, to avoid adding a fake subinclude label that also exists as a
870 // real target.
871 Set<Label> seenLabels = new HashSet<>();
872
873 // Adds all the package definition files (BUILD files and build
874 // extensions) for package "pkg", to "buildfiles".
875 for (Target x : nodes) {
876 Package pkg = x.getPackage();
nharmatabf2e2d82017-06-21 23:12:51 +0200877 if (seenPackages.add(pkg.getPackageIdentifier())) {
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +0000878 if (buildFiles) {
879 addIfUniqueLabel(pkg.getBuildFile(), seenLabels, dependentFiles);
880 }
881
882 List<Label> extensions = new ArrayList<>();
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +0000883 if (loads) {
gregce7ecc2d62020-04-17 15:32:47 -0700884 extensions.addAll(pkg.getStarlarkFileDependencies());
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +0000885 }
886
nharmata51cb8ff2018-03-26 10:40:50 -0700887 for (Label extension : extensions) {
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000888
nharmata51cb8ff2018-03-26 10:40:50 -0700889 Target loadTarget = getLoadTarget(extension, pkg);
890 addIfUniqueLabel(loadTarget, seenLabels, dependentFiles);
John Catere5fb5f02017-12-04 07:53:19 -0800891
nharmata51cb8ff2018-03-26 10:40:50 -0700892 // Also add the BUILD file of the extension.
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +0000893 if (buildFiles) {
janakrb7fecb92022-02-08 16:52:41 -0800894 Label buildFileLabel = getBuildFileLabelForPackageOfBzlFile(extension);
John Catere5fb5f02017-12-04 07:53:19 -0800895 addIfUniqueLabel(new FakeLoadTarget(buildFileLabel, pkg), seenLabels, dependentFiles);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000896 }
897 }
898 }
899 }
900 return dependentFiles;
901 }
902
janakrb7fecb92022-02-08 16:52:41 -0800903 protected Label getBuildFileLabelForPackageOfBzlFile(Label bzlFileLabel)
904 throws QueryException, InterruptedException {
905 PackageIdentifier packageIdentifier = bzlFileLabel.getPackageIdentifier();
906 PackageLookupValue packageLookupValue =
907 (PackageLookupValue) graph.getValue(PackageLookupValue.key(packageIdentifier));
908 if (packageLookupValue == null) {
909 BugReport.sendBugReport(
910 new IllegalStateException(
911 "PackageLookupValue for package of extension file "
912 + bzlFileLabel
913 + " not in graph"));
Googler3e3c8312020-07-08 15:41:39 -0700914 throw new QueryException(
janakrb7fecb92022-02-08 16:52:41 -0800915 bzlFileLabel + " does not exist in graph",
916 FailureDetail.newBuilder()
917 .setMessage("BUILD file not found on package path")
918 .setPackageLoading(
919 FailureDetails.PackageLoading.newBuilder()
920 .setCode(FailureDetails.PackageLoading.Code.BUILD_FILE_MISSING)
921 .build())
922 .build());
shreyaxd7829b12018-04-05 09:30:46 -0700923 }
janakrb7fecb92022-02-08 16:52:41 -0800924 return Label.createUnvalidated(
925 packageIdentifier,
926 packageLookupValue.getBuildFileName().getFilenameFragment().getBaseName());
shreyaxd7829b12018-04-05 09:30:46 -0700927 }
928
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000929 private static void addIfUniqueLabel(Target node, Set<Label> labels, Set<Target> nodes) {
930 if (labels.add(node.getLabel())) {
931 nodes.add(node);
932 }
933 }
934
shreyax76e4e422019-06-13 12:15:45 -0700935 protected int getVisitBatchSizeForParallelVisitation() {
936 return ParallelSkyQueryUtils.VISIT_BATCH_SIZE;
937 }
938
nharmata71c861e2019-11-08 08:38:18 -0800939 public VisitTaskStatusCallback getVisitTaskStatusCallback() {
940 return VisitTaskStatusCallback.NULL_INSTANCE;
941 }
942
nharmata51cb8ff2018-03-26 10:40:50 -0700943 private Target getLoadTarget(Label label, Package pkg) {
juliexxia93a37632017-10-26 00:55:59 +0200944 return new FakeLoadTarget(label, pkg);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000945 }
946
nharmatab9f08022019-04-23 20:36:10 -0700947 int getQueryEvaluationParallelismLevel() {
948 return queryEvaluationParallelismLevel;
949 }
950
Nathan Harmataf37750a2016-09-07 14:58:14 +0000951 @ThreadSafe
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000952 @Override
953 public TargetAccessor<Target> getAccessor() {
954 return accessor;
955 }
956
Nathan Harmataf37750a2016-09-07 14:58:14 +0000957 @ThreadSafe
John Catere5fb5f02017-12-04 07:53:19 -0800958 private Package getPackage(PackageIdentifier packageIdentifier)
959 throws InterruptedException, QueryException, NoSuchPackageException {
960 SkyKey packageKey = PackageValue.key(packageIdentifier);
shreyaxde6e9a82019-02-19 10:53:17 -0800961 PackageValue packageValue = (PackageValue) graph.getValue(packageKey);
962 if (packageValue != null) {
963 Package pkg = packageValue.getPackage();
964 if (pkg.containsErrors()) {
John Catere5fb5f02017-12-04 07:53:19 -0800965 throw new BuildFileContainsErrorsException(packageIdentifier);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000966 }
shreyaxde6e9a82019-02-19 10:53:17 -0800967 return pkg;
968 } else {
969 NoSuchPackageException exception = (NoSuchPackageException) graph.getException(packageKey);
970 if (exception != null) {
971 throw exception;
972 }
973 if (graph.isCycle(packageKey)) {
974 throw new NoSuchPackageException(packageIdentifier, "Package depends on a cycle");
975 } else {
Googler3e3c8312020-07-08 15:41:39 -0700976 throw new QueryException(packageKey + " does not exist in graph", Query.Code.CYCLE);
shreyaxde6e9a82019-02-19 10:53:17 -0800977 }
978 }
John Catere5fb5f02017-12-04 07:53:19 -0800979 }
980
981 @ThreadSafe
982 @Override
983 public Target getTarget(Label label)
984 throws TargetNotFoundException, QueryException, InterruptedException {
985 try {
986 Package pkg = getPackage(label.getPackageIdentifier());
987 return pkg.getTarget(label.getName());
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000988 } catch (NoSuchThingException e) {
Googlera697df12020-08-04 08:28:40 -0700989 throw new TargetNotFoundException(e, e.getDetailedExitCode());
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000990 }
991 }
992
nharmata2ef8de62019-04-23 18:30:55 -0700993 @Override
994 public Map<Label, Target> getTargets(Iterable<Label> labels) throws InterruptedException {
shreyaxc1407df2019-06-13 18:18:02 -0700995 if (Iterables.isEmpty(labels)) {
996 return ImmutableMap.of();
997 }
nharmata2ef8de62019-04-23 18:30:55 -0700998 Multimap<PackageIdentifier, Label> packageIdToLabelMap = ArrayListMultimap.create();
999 labels.forEach(label -> packageIdToLabelMap.put(label.getPackageIdentifier(), label));
1000 Map<PackageIdentifier, Package> packageIdToPackageMap =
1001 bulkGetPackages(packageIdToLabelMap.keySet());
1002 ImmutableMap.Builder<Label, Target> resultBuilder = ImmutableMap.builder();
shreyax76e4e422019-06-13 12:15:45 -07001003 packageSemaphore.acquireAll(packageIdToLabelMap.keySet());
1004 try {
1005 for (PackageIdentifier pkgId : packageIdToLabelMap.keySet()) {
1006 Package pkg = packageIdToPackageMap.get(pkgId);
1007 if (pkg == null) {
nharmata2ef8de62019-04-23 18:30:55 -07001008 continue;
1009 }
shreyax76e4e422019-06-13 12:15:45 -07001010 for (Label label : packageIdToLabelMap.get(pkgId)) {
1011 Target target;
1012 try {
1013 target = pkg.getTarget(label.getName());
1014 } catch (NoSuchTargetException e) {
1015 continue;
1016 }
1017 resultBuilder.put(label, target);
1018 }
nharmata2ef8de62019-04-23 18:30:55 -07001019 }
Googler2fc3d3f2022-02-01 06:29:56 -08001020 return resultBuilder.buildOrThrow();
shreyax76e4e422019-06-13 12:15:45 -07001021 } finally {
1022 packageSemaphore.releaseAll(packageIdToLabelMap.keySet());
nharmata2ef8de62019-04-23 18:30:55 -07001023 }
nharmata2ef8de62019-04-23 18:30:55 -07001024 }
1025
Nathan Harmataf37750a2016-09-07 14:58:14 +00001026 @ThreadSafe
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001027 public Map<PackageIdentifier, Package> bulkGetPackages(Iterable<PackageIdentifier> pkgIds)
1028 throws InterruptedException {
Nathan Harmata64543472016-06-30 18:33:40 +00001029 Set<SkyKey> pkgKeys = ImmutableSet.copyOf(PackageValue.keys(pkgIds));
1030 ImmutableMap.Builder<PackageIdentifier, Package> pkgResults = ImmutableMap.builder();
1031 Map<SkyKey, SkyValue> packages = graph.getSuccessfulValues(pkgKeys);
1032 for (Map.Entry<SkyKey, SkyValue> pkgEntry : packages.entrySet()) {
1033 PackageIdentifier pkgId = (PackageIdentifier) pkgEntry.getKey().argument();
1034 PackageValue pkgValue = (PackageValue) pkgEntry.getValue();
1035 pkgResults.put(pkgId, Preconditions.checkNotNull(pkgValue.getPackage(), pkgId));
1036 }
Googler2fc3d3f2022-02-01 06:29:56 -08001037 return pkgResults.buildOrThrow();
Nathan Harmata64543472016-06-30 18:33:40 +00001038 }
1039
Janak Ramakrishnane72d5222015-02-26 17:09:18 +00001040 @Override
nharmatabf2e2d82017-06-21 23:12:51 +02001041 public void buildTransitiveClosure(
janakra01210f2022-02-17 18:56:01 -08001042 QueryExpression caller, ThreadSafeMutableSet<Target> targets, OptionalInt maxDepth)
janakrb8bc2842021-12-08 12:48:02 -08001043 throws QueryException, InterruptedException {
Janak Ramakrishnane72d5222015-02-26 17:09:18 +00001044 // Everything has already been loaded, so here we just check for errors so that we can
1045 // pre-emptively throw/report if needed.
shreyax55bc5212020-01-27 11:46:39 -08001046 reportUnsuccessfulOrMissingTargetsInternal(targets, ImmutableSet.of(), caller);
1047 }
1048
1049 @Override
janakrfb744c82022-01-20 15:57:35 -08001050 protected final void preloadOrThrow(QueryExpression caller, Collection<String> patterns) {
shreyax55bc5212020-01-27 11:46:39 -08001051 // SkyQueryEnvironment directly evaluates target patterns in #getTarget and similar methods
1052 // using its graph, which is prepopulated using the universeScope (see #beforeEvaluateQuery),
1053 // so no preloading of target patterns is necessary.
1054 }
1055
1056 public void reportUnsuccessfulOrMissingTargets(
1057 Map<? extends SkyKey, Target> keysWithTargets,
1058 Set<SkyKey> allTargetKeys,
1059 QueryExpression caller)
1060 throws InterruptedException, QueryException {
1061 Set<SkyKey> missingTargets = new HashSet<>();
1062 Set<? extends SkyKey> keysFound = keysWithTargets.keySet();
1063 for (SkyKey key : allTargetKeys) {
1064 if (!keysFound.contains(key)) {
1065 missingTargets.add(key);
1066 }
1067 }
1068 reportUnsuccessfulOrMissingTargetsInternal(keysWithTargets.values(), missingTargets, caller);
1069 }
1070
1071 private void reportUnsuccessfulOrMissingTargetsInternal(
1072 Iterable<Target> targets, Iterable<SkyKey> missingTargetKeys, QueryExpression caller)
1073 throws InterruptedException, QueryException {
1074 // Targets can be in four states:
1075 // (1) Existent TransitiveTraversalValue with no error
1076 // (2) Existent TransitiveTraversalValue with an error (eg. transitive dependency error)
1077 // (3) Non-existent because it threw a SkyFunctionException
1078 // (4) Non-existent because it was never evaluated
1079 //
1080 // We first find the errors in the existent TransitiveTraversalValues that have an error. We
1081 // then find which keys correspond to SkyFunctionExceptions and extract the errors from those.
1082 // Lastly, any leftover keys are marked as missing from the graph and an error is produced.
mschaller0f61b362020-08-24 12:59:55 -07001083 ImmutableList.Builder<ErrorsToHandle> errorsBuilder = ImmutableList.builder();
1084 Set<SkyKey> successfulKeys = filterSuccessfullyLoadedTargets(targets, errorsBuilder);
shreyax55bc5212020-01-27 11:46:39 -08001085
1086 Iterable<SkyKey> keysWithTarget = makeLabels(targets);
1087 // Next, look for errors from the unsuccessfully evaluated TransitiveTraversal skyfunctions.
1088 Iterable<SkyKey> unsuccessfulKeys =
1089 Iterables.filter(keysWithTarget, Predicates.not(Predicates.in(successfulKeys)));
1090 Iterable<SkyKey> unsuccessfulOrMissingKeys =
1091 Iterables.concat(unsuccessfulKeys, missingTargetKeys);
mschaller0f61b362020-08-24 12:59:55 -07001092 processUnsuccessfulAndMissingKeys(unsuccessfulOrMissingKeys, errorsBuilder);
shreyax55bc5212020-01-27 11:46:39 -08001093
1094 // Lastly, report all found errors.
1095 if (!Iterables.isEmpty(unsuccessfulOrMissingKeys)) {
1096 eventHandler.handle(
1097 Event.warn("Targets were missing from graph: " + unsuccessfulOrMissingKeys));
1098 }
mschaller0f61b362020-08-24 12:59:55 -07001099 for (ErrorsToHandle error : errorsBuilder.build()) {
1100 handleError(caller, error.message, DetailedExitCode.of(error.failureDetail));
shreyax55bc5212020-01-27 11:46:39 -08001101 }
1102 }
1103
mschaller0f61b362020-08-24 12:59:55 -07001104 /**
1105 * An error message and a {@link FailureDetail} to include in either {@link #handleError}'s thrown
1106 * {@link QueryException} or emitted {@link Event}.
1107 */
1108 // This exists because NoSuchPackageException's #getMessage and its FailureDetail's message field
1109 // can have different contents. That fact is related to how NSPE's #getMessage dynamically adds a
1110 // prefix... which would be nice, but painstaking, to unwind.
1111 protected static class ErrorsToHandle {
1112 private final String message;
1113 private final FailureDetail failureDetail;
1114
1115 public ErrorsToHandle(String message, FailureDetail failureDetail) {
1116 this.message = message;
1117 this.failureDetail = failureDetail;
1118 }
1119 }
1120
1121 // Finds labels that were evaluated but resulted in an exception, adding any errors to the
1122 // passed-in errorsBuilder.
shreyax55bc5212020-01-27 11:46:39 -08001123 protected void processUnsuccessfulAndMissingKeys(
mschaller0f61b362020-08-24 12:59:55 -07001124 Iterable<SkyKey> unsuccessfulKeys, ImmutableList.Builder<ErrorsToHandle> errorsBuilder)
shreyax55bc5212020-01-27 11:46:39 -08001125 throws InterruptedException {
1126 Set<Map.Entry<SkyKey, Exception>> errorEntries =
1127 graph.getMissingAndExceptions(unsuccessfulKeys).entrySet();
1128 for (Map.Entry<SkyKey, Exception> entry : errorEntries) {
mschaller0f61b362020-08-24 12:59:55 -07001129 Exception exception = entry.getValue();
1130 if (exception != null) {
1131 errorsBuilder.add(
1132 new ErrorsToHandle(exception.getMessage(), createUnsuccessfulKeyFailure(exception)));
shreyax55bc5212020-01-27 11:46:39 -08001133 }
1134 }
1135 }
1136
mschaller0f61b362020-08-24 12:59:55 -07001137 protected static FailureDetail createUnsuccessfulKeyFailure(Exception exception) {
1138 return exception instanceof DetailedException
1139 ? ((DetailedException) exception).getDetailedExitCode().getFailureDetail()
1140 : FailureDetail.newBuilder()
1141 .setMessage(exception.getMessage())
1142 .setQuery(Query.newBuilder().setCode(Code.SKYQUERY_TARGET_EXCEPTION))
1143 .build();
1144 }
1145
shreyax55bc5212020-01-27 11:46:39 -08001146 // Filters for successful targets while storing error messages of unsuccessful targets.
1147 protected Set<SkyKey> filterSuccessfullyLoadedTargets(
mschaller0f61b362020-08-24 12:59:55 -07001148 Iterable<Target> targets, ImmutableList.Builder<ErrorsToHandle> errorsBuilder)
shreyax55bc5212020-01-27 11:46:39 -08001149 throws InterruptedException {
1150 Iterable<SkyKey> transitiveTraversalKeys = makeLabels(targets);
Mark Schallerc031a002015-10-21 18:17:32 +00001151
1152 // First, look for errors in the successfully evaluated TransitiveTraversalValues. They may
1153 // have encountered errors that they were able to recover from.
jcater94b87022018-05-02 09:08:52 -07001154 Set<Map.Entry<SkyKey, SkyValue>> successfulEntries =
Mark Schallerc031a002015-10-21 18:17:32 +00001155 graph.getSuccessfulValues(transitiveTraversalKeys).entrySet();
jcater96d3c912018-04-20 04:04:06 -07001156 ImmutableSet.Builder<SkyKey> successfulKeysBuilder = ImmutableSet.builder();
jcater94b87022018-05-02 09:08:52 -07001157 for (Map.Entry<SkyKey, SkyValue> successfulEntry : successfulEntries) {
Mark Schallerc031a002015-10-21 18:17:32 +00001158 successfulKeysBuilder.add(successfulEntry.getKey());
1159 TransitiveTraversalValue value = (TransitiveTraversalValue) successfulEntry.getValue();
janakrf091f9c2019-03-25 13:42:18 -07001160 String errorMessage = value.getErrorMessage();
1161 if (errorMessage != null) {
mschaller0f61b362020-08-24 12:59:55 -07001162 FailureDetail failureDetail =
1163 FailureDetail.newBuilder()
1164 .setMessage(errorMessage)
1165 .setQuery(Query.newBuilder().setCode(Code.SKYQUERY_TRANSITIVE_TARGET_ERROR))
1166 .build();
1167 errorsBuilder.add(new ErrorsToHandle(errorMessage, failureDetail));
Mark Schallerc031a002015-10-21 18:17:32 +00001168 }
1169 }
shreyax55bc5212020-01-27 11:46:39 -08001170 return successfulKeysBuilder.build();
Janak Ramakrishnane72d5222015-02-26 17:09:18 +00001171 }
1172
shreyax2643d4b2018-05-25 11:12:11 -07001173 public ExtendedEventHandler getEventHandler() {
1174 return eventHandler;
1175 }
nharmata398e6dab2018-04-12 15:31:26 -07001176
shreyax6bebe382019-11-13 06:26:26 -08001177 public static final Predicate<SkyKey> IS_LABEL =
shreyax2643d4b2018-05-25 11:12:11 -07001178 SkyFunctionName.functionIs(Label.TRANSITIVE_TRAVERSAL);
1179
1180 public static final Function<SkyKey, Label> SKYKEY_TO_LABEL =
jhorvitzdd1d8412020-08-01 05:59:14 -07001181 skyKey -> IS_LABEL.test(skyKey) ? (Label) skyKey.argument() : null;
nharmata398e6dab2018-04-12 15:31:26 -07001182
Nathan Harmata41b54172016-11-10 18:54:09 +00001183 static final Function<SkyKey, PackageIdentifier> PACKAGE_SKYKEY_TO_PACKAGE_IDENTIFIER =
laurentlb3d2a68c2017-06-30 00:32:04 +02001184 skyKey -> (PackageIdentifier) skyKey.argument();
Nathan Harmata41b54172016-11-10 18:54:09 +00001185
nharmata7c56dce2018-08-16 10:50:26 -07001186 public static Multimap<SkyKey, SkyKey> makePackageKeyToTargetKeyMap(Iterable<SkyKey> keys) {
Janak Ramakrishnane933d5e2016-01-08 16:43:54 +00001187 Multimap<SkyKey, SkyKey> packageKeyToTargetKeyMap = ArrayListMultimap.create();
1188 for (SkyKey key : keys) {
1189 Label label = SKYKEY_TO_LABEL.apply(key);
Janak Ramakrishnanb5a541a2015-06-19 20:55:01 +00001190 if (label == null) {
Janak Ramakrishnan36858732015-06-17 16:45:47 +00001191 continue;
1192 }
Mark Schaller4b801f22016-06-21 22:26:12 +00001193 packageKeyToTargetKeyMap.put(PackageValue.key(label.getPackageIdentifier()), key);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +00001194 }
Nathan Harmata41b54172016-11-10 18:54:09 +00001195 return packageKeyToTargetKeyMap;
1196 }
1197
nharmata7c56dce2018-08-16 10:50:26 -07001198 public static Set<PackageIdentifier> getPkgIdsNeededForTargetification(
1199 Multimap<SkyKey, SkyKey> packageKeyToTargetKeyMap) {
janakrb8bc2842021-12-08 12:48:02 -08001200 return packageKeyToTargetKeyMap.keySet().stream()
nharmata7c56dce2018-08-16 10:50:26 -07001201 .map(SkyQueryEnvironment.PACKAGE_SKYKEY_TO_PACKAGE_IDENTIFIER)
1202 .collect(toImmutableSet());
Nathan Harmata41b54172016-11-10 18:54:09 +00001203 }
1204
1205 @ThreadSafe
nharmata7c56dce2018-08-16 10:50:26 -07001206 public Map<SkyKey, Target> getTargetKeyToTargetMapForPackageKeyToTargetKeyMap(
Nathan Harmata41b54172016-11-10 18:54:09 +00001207 Multimap<SkyKey, SkyKey> packageKeyToTargetKeyMap) throws InterruptedException {
nharmata641db6d2018-08-16 14:31:57 -07001208 ImmutableMap.Builder<SkyKey, Target> resultBuilder = ImmutableMap.builder();
1209 getTargetsForPackageKeyToTargetKeyMapHelper(packageKeyToTargetKeyMap, resultBuilder::put);
Googler2fc3d3f2022-02-01 06:29:56 -08001210 return resultBuilder.buildOrThrow();
nharmata641db6d2018-08-16 14:31:57 -07001211 }
1212
1213 @ThreadSafe
1214 public Multimap<PackageIdentifier, Target> getPkgIdToTargetMultimapForPackageKeyToTargetKeyMap(
1215 Multimap<SkyKey, SkyKey> packageKeyToTargetKeyMap) throws InterruptedException {
1216 Multimap<PackageIdentifier, Target> result = ArrayListMultimap.create();
1217 getTargetsForPackageKeyToTargetKeyMapHelper(
janakrb8bc2842021-12-08 12:48:02 -08001218 packageKeyToTargetKeyMap, (k, t) -> result.put(t.getLabel().getPackageIdentifier(), t));
nharmata641db6d2018-08-16 14:31:57 -07001219 return result;
1220 }
1221
1222 private void getTargetsForPackageKeyToTargetKeyMapHelper(
1223 Multimap<SkyKey, SkyKey> packageKeyToTargetKeyMap,
janakrb8bc2842021-12-08 12:48:02 -08001224 BiConsumer<SkyKey, Target> targetKeyAndTargetConsumer)
1225 throws InterruptedException {
Googler2b503882016-11-28 21:54:43 +00001226 Set<SkyKey> processedTargets = new HashSet<>();
Miguel Alcon Pinto45820872015-09-11 19:57:47 +00001227 Map<SkyKey, SkyValue> packageMap = graph.getSuccessfulValues(packageKeyToTargetKeyMap.keySet());
Janak Ramakrishnan36858732015-06-17 16:45:47 +00001228 for (Map.Entry<SkyKey, SkyValue> entry : packageMap.entrySet()) {
nharmata641db6d2018-08-16 14:31:57 -07001229 Package pkg = ((PackageValue) entry.getValue()).getPackage();
Janak Ramakrishnane933d5e2016-01-08 16:43:54 +00001230 for (SkyKey targetKey : packageKeyToTargetKeyMap.get(entry.getKey())) {
Googler2b503882016-11-28 21:54:43 +00001231 if (processedTargets.add(targetKey)) {
1232 try {
nharmata641db6d2018-08-16 14:31:57 -07001233 Target target = pkg.getTarget(SKYKEY_TO_LABEL.apply(targetKey).getName());
1234 targetKeyAndTargetConsumer.accept(targetKey, target);
Googler2b503882016-11-28 21:54:43 +00001235 } catch (NoSuchTargetException e) {
1236 // Skip missing target.
1237 }
Janak Ramakrishnan36858732015-06-17 16:45:47 +00001238 }
1239 }
1240 }
Janak Ramakrishnan36858732015-06-17 16:45:47 +00001241 }
1242
Nathan Harmataf44211c2016-10-10 16:31:18 +00001243 static final Function<Target, SkyKey> TARGET_TO_SKY_KEY =
laurentlb3d2a68c2017-06-30 00:32:04 +02001244 target -> TransitiveTraversalValue.key(target.getLabel());
Janak Ramakrishnana40e7b72015-08-20 20:06:16 +00001245
shreyax55bc5212020-01-27 11:46:39 -08001246 /** A strict (i.e. non-lazy) variant of {@link #makeLabels}. */
1247 public static <T extends Target> Iterable<SkyKey> makeLabelsStrict(Iterable<T> targets) {
1248 return ImmutableList.copyOf(makeLabels(targets));
Nathan Harmata39900802016-09-20 21:06:59 +00001249 }
1250
shreyax55bc5212020-01-27 11:46:39 -08001251 protected static <T extends Target> Iterable<SkyKey> makeLabels(Iterable<T> targets) {
Janak Ramakrishnana40e7b72015-08-20 20:06:16 +00001252 return Iterables.transform(targets, TARGET_TO_SKY_KEY);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +00001253 }
1254
Janak Ramakrishnane72d5222015-02-26 17:09:18 +00001255 @Override
1256 public Target getOrCreate(Target target) {
1257 return target;
1258 }
Janak Ramakrishnan643063d2015-06-25 16:21:49 +00001259
shreyax76e4e422019-06-13 12:15:45 -07001260 protected Iterable<Target> getBuildFileTargetsForPackageKeys(
1261 Set<PackageIdentifier> pkgIds, QueryExpressionContext<Target> context)
nharmata1bd4aaf2017-10-31 11:23:04 -04001262 throws QueryException, InterruptedException {
nharmata1bd4aaf2017-10-31 11:23:04 -04001263 packageSemaphore.acquireAll(pkgIds);
1264 try {
shreyax76e4e422019-06-13 12:15:45 -07001265 return Iterables.transform(
1266 graph.getSuccessfulValues(PackageValue.keys(pkgIds)).values(),
1267 skyValue -> ((PackageValue) skyValue).getPackage().getBuildFile());
nharmata1bd4aaf2017-10-31 11:23:04 -04001268 } finally {
1269 packageSemaphore.releaseAll(pkgIds);
1270 }
1271 }
1272
mschaller096b7072018-05-01 14:49:22 -07001273 /**
nharmata20efb2a2018-09-28 12:54:12 -07001274 * Calculates the set of packages whose evaluation transitively depends on (e.g. via 'load'
1275 * statements) the contents of the specified paths. The emitted {@link Target}s are BUILD file
1276 * targets.
mschaller096b7072018-05-01 14:49:22 -07001277 */
Nathan Harmata593dc522016-09-28 23:35:46 +00001278 @ThreadSafe
mschaller096b7072018-05-01 14:49:22 -07001279 QueryTaskFuture<Void> getRBuildFiles(
nharmata20efb2a2018-09-28 12:54:12 -07001280 Collection<PathFragment> fileIdentifiers,
1281 QueryExpressionContext<Target> context,
1282 Callback<Target> callback) {
laurentlb3d2a68c2017-06-30 00:32:04 +02001283 return QueryTaskFutureImpl.ofDelegate(
1284 safeSubmit(
1285 () -> {
1286 ParallelSkyQueryUtils.getRBuildFilesParallel(
nharmata20efb2a2018-09-28 12:54:12 -07001287 SkyQueryEnvironment.this, fileIdentifiers, context, callback);
laurentlb3d2a68c2017-06-30 00:32:04 +02001288 return null;
1289 }));
Nathan Harmata593dc522016-09-28 23:35:46 +00001290 }
1291
Janak Ramakrishnan643063d2015-06-25 16:21:49 +00001292 @Override
1293 public Iterable<QueryFunction> getFunctions() {
1294 return ImmutableList.<QueryFunction>builder()
Janak Ramakrishnand802d5b2015-08-20 21:05:46 +00001295 .addAll(super.getFunctions())
1296 .add(new AllRdepsFunction())
1297 .add(new RBuildFilesFunction())
1298 .build();
Janak Ramakrishnan643063d2015-06-25 16:21:49 +00001299 }
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +00001300
kkress1847a012020-06-24 12:30:11 -07001301 private static class IgnoredPatternSupplier
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001302 implements InterruptibleSupplier<ImmutableSet<PathFragment>> {
Mark Schaller6cebed62016-06-27 18:05:39 +00001303 private final WalkableGraph graph;
1304
kkress1847a012020-06-24 12:30:11 -07001305 private IgnoredPatternSupplier(WalkableGraph graph) {
Mark Schaller6cebed62016-06-27 18:05:39 +00001306 this.graph = graph;
1307 }
1308
1309 @Override
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001310 public ImmutableSet<PathFragment> get() throws InterruptedException {
kkress1847a012020-06-24 12:30:11 -07001311 return ((IgnoredPackagePrefixesValue) graph.getValue(IgnoredPackagePrefixesValue.key()))
Mark Schaller6cebed62016-06-27 18:05:39 +00001312 .getPatterns();
1313 }
1314 }
1315
Nathan Harmatae9826b42017-03-07 18:05:21 +00001316 private static class SkyKeyKeyExtractor implements KeyExtractor<SkyKey, SkyKey> {
1317 private static final SkyKeyKeyExtractor INSTANCE = new SkyKeyKeyExtractor();
1318
janakrb8bc2842021-12-08 12:48:02 -08001319 private SkyKeyKeyExtractor() {}
Mark Schaller20c75012016-06-21 22:51:14 +00001320
1321 @Override
Nathan Harmatae9826b42017-03-07 18:05:21 +00001322 public SkyKey extractKey(SkyKey element) {
Nathan Harmata29bc3fb2016-09-09 16:11:12 +00001323 return element;
Mark Schaller20c75012016-06-21 22:51:14 +00001324 }
1325 }
1326
Mark Schaller4d8baf82016-06-21 18:56:04 +00001327 /**
1328 * Wraps a {@link Callback} and guarantees that all calls to the original will have at least
1329 * {@code batchThreshold} {@link Target}s, except for the final such call.
1330 *
1331 * <p>Retains fewer than {@code batchThreshold} {@link Target}s at a time.
1332 *
1333 * <p>After this object's {@link #process} has been called for the last time, {#link
1334 * #processLastPending} must be called to "flush" any remaining {@link Target}s through to the
1335 * original.
Mark Schaller20c75012016-06-21 22:51:14 +00001336 *
Googlerb3610d52016-10-24 19:18:36 +00001337 * <p>This callback may be called from multiple threads concurrently. At most one thread will call
1338 * the wrapped {@code callback} concurrently.
Mark Schaller4d8baf82016-06-21 18:56:04 +00001339 */
Nathan Harmata7a5a2362017-03-08 22:42:01 +00001340 // TODO(nharmata): For queries with less than {@code batchThreshold} results, this batching
1341 // strategy probably hurts performance since we can only start formatting results once the entire
1342 // query is finished.
nharmata1bd4aaf2017-10-31 11:23:04 -04001343 // TODO(nharmata): This batching strategy is also potentially harmful from a memory perspective
1344 // since when the Targets being output are backed by Package instances, we're delaying GC of the
1345 // Package instances until the output batch size is met.
Nathan Harmata7a5a2362017-03-08 22:42:01 +00001346 private static class BatchStreamedCallback extends ThreadSafeOutputFormatterCallback<Target>
1347 implements Callback<Target> {
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +00001348
Nathan Harmata7a5a2362017-03-08 22:42:01 +00001349 // TODO(nharmata): Now that we know the wrapped callback is ThreadSafe, there's no correctness
1350 // concern that requires the prohibition of concurrent uses of the callback; the only concern is
1351 // memory. We should have a threshold for when to invoke the callback with a batch, and also a
Mark Schaller4f48f1b2017-03-10 20:38:43 +00001352 // separate, larger, bound on the number of targets being processed at the same time.
Nathan Harmata7a5a2362017-03-08 22:42:01 +00001353 private final ThreadSafeOutputFormatterCallback<Target> callback;
nharmatac49e8742018-09-27 11:27:41 -07001354 private final NonExceptionalUniquifier<Target> uniquifier;
Mark Schaller20c75012016-06-21 22:51:14 +00001355 private final Object pendingLock = new Object();
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +00001356 private List<Target> pending = new ArrayList<>();
1357 private int batchThreshold;
1358
Nathan Harmata7a5a2362017-03-08 22:42:01 +00001359 private BatchStreamedCallback(
1360 ThreadSafeOutputFormatterCallback<Target> callback,
nharmatafac7c252018-09-12 15:31:23 -07001361 int batchThreshold,
nharmatac49e8742018-09-27 11:27:41 -07001362 NonExceptionalUniquifier<Target> uniquifier) {
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +00001363 this.callback = callback;
1364 this.batchThreshold = batchThreshold;
nharmatafac7c252018-09-12 15:31:23 -07001365 this.uniquifier = uniquifier;
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +00001366 }
1367
1368 @Override
Nathan Harmata5bb9cc92016-09-30 21:28:30 +00001369 public void start() throws IOException {
1370 callback.start();
1371 }
1372
1373 @Override
1374 public void processOutput(Iterable<Target> partialResult)
1375 throws IOException, InterruptedException {
Mark Schaller20c75012016-06-21 22:51:14 +00001376 ImmutableList<Target> uniquifiedTargets = uniquifier.unique(partialResult);
nharmata2e8d43d2019-01-15 10:21:14 -08001377 Iterable<Target> toProcess = null;
Mark Schaller20c75012016-06-21 22:51:14 +00001378 synchronized (pendingLock) {
1379 Preconditions.checkNotNull(pending, "Reuse of the callback is not allowed");
1380 pending.addAll(uniquifiedTargets);
1381 if (pending.size() >= batchThreshold) {
nharmata2e8d43d2019-01-15 10:21:14 -08001382 toProcess = pending;
Mark Schaller20c75012016-06-21 22:51:14 +00001383 pending = new ArrayList<>();
1384 }
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +00001385 }
nharmata2e8d43d2019-01-15 10:21:14 -08001386 if (toProcess != null) {
1387 callback.processOutput(toProcess);
1388 }
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +00001389 }
1390
Nathan Harmata5bb9cc92016-09-30 21:28:30 +00001391 @Override
Nathan Harmataa2565aa2016-11-17 22:37:33 +00001392 public void close(boolean failFast) throws IOException, InterruptedException {
1393 if (!failFast) {
1394 processLastPending();
1395 }
1396 callback.close(failFast);
Nathan Harmata5bb9cc92016-09-30 21:28:30 +00001397 }
1398
1399 private void processLastPending() throws IOException, InterruptedException {
Mark Schaller20c75012016-06-21 22:51:14 +00001400 synchronized (pendingLock) {
1401 if (!pending.isEmpty()) {
Nathan Harmata5bb9cc92016-09-30 21:28:30 +00001402 callback.processOutput(pending);
Mark Schaller20c75012016-06-21 22:51:14 +00001403 pending = null;
1404 }
Miguel Alcon Pinto47ea9482015-11-18 16:05:17 +00001405 }
1406 }
1407 }
Googlerd1911622016-06-27 15:43:11 +00001408
Nathan Harmataf37750a2016-09-07 14:58:14 +00001409 @ThreadSafe
Googlerd1911622016-06-27 15:43:11 +00001410 @Override
Nathan Harmata7a5a2362017-03-08 22:42:01 +00001411 public QueryTaskFuture<Void> getAllRdepsUnboundedParallel(
Nathan Harmata593dc522016-09-28 23:35:46 +00001412 QueryExpression expression,
shreyax159a6112018-06-12 15:34:09 -07001413 QueryExpressionContext<Target> context,
Nathan Harmata7a5a2362017-03-08 22:42:01 +00001414 Callback<Target> callback) {
shreyax76e4e422019-06-13 12:15:45 -07001415 return ParallelSkyQueryUtils.getAllRdepsUnboundedParallel(this, expression, context, callback);
Nathan Harmata593dc522016-09-28 23:35:46 +00001416 }
1417
nharmata398e6dab2018-04-12 15:31:26 -07001418 @ThreadSafe
Googler96f95cc2017-09-02 00:54:18 +02001419 @Override
nharmata398e6dab2018-04-12 15:31:26 -07001420 public QueryTaskFuture<Void> getAllRdepsBoundedParallel(
Googler96f95cc2017-09-02 00:54:18 +02001421 QueryExpression expression,
nharmata398e6dab2018-04-12 15:31:26 -07001422 int depth,
shreyax159a6112018-06-12 15:34:09 -07001423 QueryExpressionContext<Target> context,
Googler96f95cc2017-09-02 00:54:18 +02001424 Callback<Target> callback) {
nharmata398e6dab2018-04-12 15:31:26 -07001425 return ParallelSkyQueryUtils.getAllRdepsBoundedParallel(
shreyax76e4e422019-06-13 12:15:45 -07001426 this, expression, depth, context, callback);
nharmata398e6dab2018-04-12 15:31:26 -07001427 }
1428
nharmatab6bf51d2018-07-27 13:49:45 -07001429 protected QueryTaskFuture<Predicate<SkyKey>> getUnfilteredUniverseDTCSkyKeyPredicateFuture(
shreyax159a6112018-06-12 15:34:09 -07001430 QueryExpression universe, QueryExpressionContext<Target> context) {
nharmata398e6dab2018-04-12 15:31:26 -07001431 return ParallelSkyQueryUtils.getDTCSkyKeyPredicateFuture(
janakrb8bc2842021-12-08 12:48:02 -08001432 this, universe, context, BATCH_CALLBACK_SIZE, queryEvaluationParallelismLevel);
Googler96f95cc2017-09-02 00:54:18 +02001433 }
1434
Nathan Harmata593dc522016-09-28 23:35:46 +00001435 @ThreadSafe
1436 @Override
nharmata398e6dab2018-04-12 15:31:26 -07001437 public QueryTaskFuture<Void> getRdepsUnboundedParallel(
Googlerd1911622016-06-27 15:43:11 +00001438 QueryExpression expression,
nharmata398e6dab2018-04-12 15:31:26 -07001439 QueryExpression universe,
shreyax159a6112018-06-12 15:34:09 -07001440 QueryExpressionContext<Target> context,
nharmata398e6dab2018-04-12 15:31:26 -07001441 Callback<Target> callback) {
1442 return transformAsync(
nharmata10911f12018-08-08 07:58:21 -07001443 // Even if we need to do edge filtering, it's fine to construct the rdeps universe via an
1444 // unfiltered DTC visitation; the subsequent rdeps visitation will perform the edge
1445 // filtering.
nharmatab6bf51d2018-07-27 13:49:45 -07001446 getUnfilteredUniverseDTCSkyKeyPredicateFuture(universe, context),
shreyax76e4e422019-06-13 12:15:45 -07001447 unfilteredUniversePredicate ->
1448 ParallelSkyQueryUtils.getRdepsInUniverseUnboundedParallel(
1449 this, expression, unfilteredUniversePredicate, context, callback));
Googlerd1911622016-06-27 15:43:11 +00001450 }
1451
shreyax2643d4b2018-05-25 11:12:11 -07001452 @Override
1453 public QueryTaskFuture<Void> getDepsUnboundedParallel(
1454 QueryExpression expression,
shreyax159a6112018-06-12 15:34:09 -07001455 QueryExpressionContext<Target> context,
shreyax55bc5212020-01-27 11:46:39 -08001456 Callback<Target> callback,
1457 QueryExpression caller) {
shreyax2643d4b2018-05-25 11:12:11 -07001458 return ParallelSkyQueryUtils.getDepsUnboundedParallel(
1459 SkyQueryEnvironment.this,
1460 expression,
1461 context,
1462 callback,
shreyax55bc5212020-01-27 11:46:39 -08001463 /*depsNeedFiltering=*/ !dependencyFilter.equals(DependencyFilter.ALL_DEPS),
1464 caller);
shreyax2643d4b2018-05-25 11:12:11 -07001465 }
1466
nharmata398e6dab2018-04-12 15:31:26 -07001467 @ThreadSafe
1468 @Override
1469 public QueryTaskFuture<Void> getRdepsBoundedParallel(
Googlerd1911622016-06-27 15:43:11 +00001470 QueryExpression expression,
Nathan Harmatabc47f402016-07-13 16:22:30 +00001471 int depth,
nharmata398e6dab2018-04-12 15:31:26 -07001472 QueryExpression universe,
shreyax159a6112018-06-12 15:34:09 -07001473 QueryExpressionContext<Target> context,
nharmata398e6dab2018-04-12 15:31:26 -07001474 Callback<Target> callback) {
1475 return transformAsync(
nharmata10911f12018-08-08 07:58:21 -07001476 // Even if we need to do edge filtering, it's fine to construct the rdeps universe via an
1477 // unfiltered DTC visitation; the subsequent rdeps visitation will perform the edge
1478 // filtering.
nharmatab6bf51d2018-07-27 13:49:45 -07001479 getUnfilteredUniverseDTCSkyKeyPredicateFuture(universe, context),
shreyax76e4e422019-06-13 12:15:45 -07001480 universePredicate ->
1481 ParallelSkyQueryUtils.getRdepsInUniverseBoundedParallel(
1482 this, expression, depth, universePredicate, context, callback));
Googlerd1911622016-06-27 15:43:11 +00001483 }
Mark Schaller4f48f1b2017-03-10 20:38:43 +00001484
1485 /**
1486 * Query evaluation behavior is specified with respect to errors it emits. (Or at least it should
1487 * be. Tools rely on it.) Notably, errors that occur during evaluation of a query's universe must
1488 * not be emitted during query command evaluation. Consider the case of a simple single target
1489 * query when {@code //...} is the universe: errors in far flung parts of the workspace should not
1490 * be emitted when that query command is evaluated.
1491 *
1492 * <p>Non-error message events are not specified. For instance, it's useful (and expected by some
1493 * unit tests that should know better) for query commands to emit {@link EventKind#PROGRESS}
1494 * events during package loading.
1495 *
1496 * <p>Therefore, this class is used to forward only non-{@link EventKind#ERROR} events during
1497 * universe loading to the {@link SkyQueryEnvironment}'s {@link ExtendedEventHandler}.
1498 */
1499 protected static class ErrorBlockingForwardingEventHandler extends DelegatingEventHandler {
1500
1501 public ErrorBlockingForwardingEventHandler(ExtendedEventHandler delegate) {
1502 super(delegate);
1503 }
1504
1505 @Override
1506 public void handle(Event e) {
1507 if (!e.getKind().equals(EventKind.ERROR)) {
1508 super.handle(e);
1509 }
1510 }
1511 }
Janak Ramakrishnane72d5222015-02-26 17:09:18 +00001512}