// Copyright 2014 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.skyframe; import static com.google.devtools.build.lib.concurrent.Uninterruptibles.callUninterruptibly; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Stopwatch; import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Range; import com.google.common.eventbus.EventBus; import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.actions.ActionCacheChecker; import com.google.devtools.build.lib.actions.ActionExecutionContextFactory; import com.google.devtools.build.lib.actions.ActionExecutionStatusReporter; import com.google.devtools.build.lib.actions.ActionGraph; import com.google.devtools.build.lib.actions.ActionInputFileCache; import com.google.devtools.build.lib.actions.ActionInputPrefetcher; import com.google.devtools.build.lib.actions.ActionLogBufferPathGenerator; import com.google.devtools.build.lib.actions.ActionLookupValue; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ArtifactFactory; import com.google.devtools.build.lib.actions.ArtifactOwner; import com.google.devtools.build.lib.actions.EnvironmentalExecException; import com.google.devtools.build.lib.actions.Executor; import com.google.devtools.build.lib.actions.ResourceManager; import com.google.devtools.build.lib.actions.Root; import com.google.devtools.build.lib.analysis.AspectCollection; import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.BuildView.Options; import com.google.devtools.build.lib.analysis.ConfiguredAspect; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.Dependency; import com.google.devtools.build.lib.analysis.ToolchainContext; import com.google.devtools.build.lib.analysis.TopLevelArtifactContext; import com.google.devtools.build.lib.analysis.WorkspaceStatusAction; import com.google.devtools.build.lib.analysis.WorkspaceStatusAction.Factory; import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory; import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey; import com.google.devtools.build.lib.analysis.config.BinTools; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory; import com.google.devtools.build.lib.analysis.config.ConfigurationResolver; import com.google.devtools.build.lib.analysis.config.HostTransition; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.analysis.config.PatchTransition; import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget; import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.DuplicateException; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.cmdline.TargetParsingException; import com.google.devtools.build.lib.concurrent.ThreadSafety; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible; import com.google.devtools.build.lib.events.ErrorSensingEventHandler; import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.events.Reporter; import com.google.devtools.build.lib.packages.AspectDescriptor; import com.google.devtools.build.lib.packages.AstAfterPreprocessing; import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition; import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.NoSuchThingException; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.Package.Builder; import com.google.devtools.build.lib.packages.PackageFactory; import com.google.devtools.build.lib.packages.RuleClassProvider; import com.google.devtools.build.lib.packages.RuleVisibility; import com.google.devtools.build.lib.pkgcache.LoadingCallback; import com.google.devtools.build.lib.pkgcache.LoadingFailedException; import com.google.devtools.build.lib.pkgcache.LoadingOptions; import com.google.devtools.build.lib.pkgcache.LoadingPhaseCompleteEvent; import com.google.devtools.build.lib.pkgcache.LoadingPhaseRunner; import com.google.devtools.build.lib.pkgcache.LoadingResult; import com.google.devtools.build.lib.pkgcache.PackageCacheOptions; import com.google.devtools.build.lib.pkgcache.PackageManager; import com.google.devtools.build.lib.pkgcache.PackageManager.PackageManagerStatistics; import com.google.devtools.build.lib.pkgcache.PathPackageLocator; import com.google.devtools.build.lib.pkgcache.TargetParsingPhaseTimeEvent; import com.google.devtools.build.lib.pkgcache.TestFilter; import com.google.devtools.build.lib.pkgcache.TransitivePackageLoader; import com.google.devtools.build.lib.profiler.AutoProfiler; import com.google.devtools.build.lib.skyframe.AspectValue.AspectValueKey; import com.google.devtools.build.lib.skyframe.DirtinessCheckerUtils.FileDirtinessChecker; import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction; import com.google.devtools.build.lib.skyframe.PackageFunction.ActionOnIOExceptionReadingBuildFile; import com.google.devtools.build.lib.skyframe.PackageFunction.CacheEntryWithGlobDeps; import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy; import com.google.devtools.build.lib.skyframe.PackageLookupValue.BuildFileName; import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ActionCompletedReceiver; import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ProgressSupplier; import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; import com.google.devtools.build.lib.skyframe.ToolchainUtil.ToolchainContextException; import com.google.devtools.build.lib.syntax.SkylarkSemanticsOptions; import com.google.devtools.build.lib.util.AbruptExitException; import com.google.devtools.build.lib.util.ExitCode; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.util.ResourceUsage; import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor; import com.google.devtools.build.lib.vfs.BatchStat; import com.google.devtools.build.lib.vfs.Dirent; import com.google.devtools.build.lib.vfs.FileSystem; import com.google.devtools.build.lib.vfs.ModifiedFileSet; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.lib.vfs.UnixGlob; import com.google.devtools.build.skyframe.BuildDriver; import com.google.devtools.build.skyframe.CycleInfo; import com.google.devtools.build.skyframe.CyclesReporter; import com.google.devtools.build.skyframe.Differencer; import com.google.devtools.build.skyframe.Differencer.DiffWithDelta.Delta; import com.google.devtools.build.skyframe.ErrorInfo; import com.google.devtools.build.skyframe.EvaluationProgressReceiver; import com.google.devtools.build.skyframe.EvaluationResult; import com.google.devtools.build.skyframe.ImmutableDiff; import com.google.devtools.build.skyframe.Injectable; import com.google.devtools.build.skyframe.MemoizingEvaluator; import com.google.devtools.build.skyframe.MemoizingEvaluator.EvaluatorSupplier; import com.google.devtools.build.skyframe.SkyFunction; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; import com.google.devtools.build.skyframe.WalkableGraph.WalkableGraphFactory; import com.google.devtools.common.options.OptionsClassProvider; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; import javax.annotation.Nullable; /** * A helper object to support Skyframe-driven execution. * *

This object is mostly used to inject external state, such as the executor engine or * some additional artifacts (workspace status and build info artifacts) into SkyFunctions * for use during the build. */ public abstract class SkyframeExecutor implements WalkableGraphFactory { private final EvaluatorSupplier evaluatorSupplier; protected MemoizingEvaluator memoizingEvaluator; private final MemoizingEvaluator.EmittedEventState emittedEventState = new MemoizingEvaluator.EmittedEventState(); private final PackageFactory pkgFactory; private final WorkspaceStatusAction.Factory workspaceStatusActionFactory; private final BlazeDirectories directories; protected final ExternalFilesHelper externalFilesHelper; @Nullable private OutputService outputService; // TODO(bazel-team): Figure out how to handle value builders that block internally. Blocking // operations may need to be handled in another (bigger?) thread pool. Also, we should detect // the number of cores and use that as the thread-pool size for CPU-bound operations. // I just bumped this to 200 to get reasonable execution phase performance; that may cause // significant overhead for CPU-bound processes (i.e. analysis). [skyframe-analysis] @VisibleForTesting public static final int DEFAULT_THREAD_COUNT = // Reduce thread count while running tests of Bazel. Test cases are typically small, and large // thread pools vying for a relatively small number of CPU cores may induce non-optimal // performance. System.getenv("TEST_TMPDIR") == null ? 200 : 5; // Cache of partially constructed Package instances, stored between reruns of the PackageFunction // (because of missing dependencies, within the same evaluate() run) to avoid loading the same // package twice (first time loading to find subincludes and declare value dependencies). // TODO(bazel-team): remove this cache once we have skyframe-native package loading // [skyframe-loading] private final Cache> packageFunctionCache = newPkgFunctionCache(); private final Cache> astCache = newAstCache(); private final AtomicInteger numPackagesLoaded = new AtomicInteger(0); private final PackageProgressReceiver packageProgress = new PackageProgressReceiver(); protected SkyframeBuildView skyframeBuildView; private ActionLogBufferPathGenerator actionLogBufferPathGenerator; protected BuildDriver buildDriver; // AtomicReferences are used here as mutable boxes shared with value builders. private final AtomicBoolean showLoadingProgress = new AtomicBoolean(); protected final AtomicReference syscalls = new AtomicReference<>(UnixGlob.DEFAULT_SYSCALLS); protected final AtomicReference pkgLocator = new AtomicReference<>(); protected final AtomicReference> deletedPackages = new AtomicReference<>(ImmutableSet.of()); private final AtomicReference eventBus = new AtomicReference<>(); protected final AtomicReference tsgm = new AtomicReference<>(); protected final AtomicReference> clientEnv = new AtomicReference<>(); private final ImmutableMap buildInfoFactories; // Under normal circumstances, the artifact factory persists for the life of a Blaze server, but // since it is not yet created when we create the value builders, we have to use a supplier, // initialized when the build view is created. private final MutableSupplier artifactFactory = new MutableSupplier<>(); // Used to give to WriteBuildInfoAction via a supplier. Relying on BuildVariableValue.BUILD_ID // would be preferable, but we have no way to have the Action depend on that value directly. // Having the BuildInfoFunction own the supplier is currently not possible either, because then // it would be invalidated on every build, since it would depend on the build id value. private MutableSupplier buildId = new MutableSupplier<>(); protected boolean active = true; private final SkyframePackageManager packageManager; private final ResourceManager resourceManager; /** Used to lock evaluator on legacy calls to get existing values. */ private final Object valueLookupLock = new Object(); private final AtomicReference statusReporterRef = new AtomicReference<>(); private final SkyframeActionExecutor skyframeActionExecutor; private CompletionReceiver actionExecutionFunction; protected SkyframeProgressReceiver progressReceiver; private final AtomicReference cyclesReporter = new AtomicReference<>(); private final BinTools binTools; private boolean needToInjectEmbeddedArtifacts = true; private boolean needToInjectPrecomputedValuesForAnalysis = true; protected int modifiedFiles; protected int outputDirtyFiles; protected int modifiedFilesDuringPreviousBuild; private final Predicate allowedMissingInputs; private final ExternalFileAction externalFileAction; private final ImmutableMap extraSkyFunctions; private final ImmutableList extraPrecomputedValues; protected SkyframeIncrementalBuildMonitor incrementalBuildMonitor = new SkyframeIncrementalBuildMonitor(); protected final MutableSupplier removeActionsAfterEvaluation = new MutableSupplier<>(); private MutableSupplier> configurationFragments = new MutableSupplier<>(); private final PathFragment blacklistedPackagePrefixesFile; private final RuleClassProvider ruleClassProvider; private final CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy; private final List buildFilesByPriority; private final ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile; private PerBuildSyscallCache perBuildSyscallCache; private int lastConcurrencyLevel = -1; private static final Logger logger = Logger.getLogger(SkyframeExecutor.class.getName()); protected SkyframeExecutor( EvaluatorSupplier evaluatorSupplier, PackageFactory pkgFactory, BlazeDirectories directories, BinTools binTools, Factory workspaceStatusActionFactory, ImmutableList buildInfoFactories, Predicate allowedMissingInputs, ImmutableMap extraSkyFunctions, ImmutableList extraPrecomputedValues, ExternalFileAction externalFileAction, PathFragment blacklistedPackagePrefixesFile, CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy, List buildFilesByPriority, ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile) { // Strictly speaking, these arguments are not required for initialization, but all current // callsites have them at hand, so we might as well set them during construction. this.evaluatorSupplier = evaluatorSupplier; this.pkgFactory = pkgFactory; this.pkgFactory.setSyscalls(syscalls); this.workspaceStatusActionFactory = workspaceStatusActionFactory; this.packageManager = new SkyframePackageManager( new SkyframePackageLoader(), new SkyframeTransitivePackageLoader(), syscalls, cyclesReporter, pkgLocator, numPackagesLoaded, this); this.resourceManager = ResourceManager.instance(); this.skyframeActionExecutor = new SkyframeActionExecutor(eventBus, statusReporterRef); this.directories = Preconditions.checkNotNull(directories); ImmutableMap.Builder factoryMapBuilder = ImmutableMap.builder(); for (BuildInfoFactory factory : buildInfoFactories) { factoryMapBuilder.put(factory.getKey(), factory); } this.buildInfoFactories = factoryMapBuilder.build(); this.allowedMissingInputs = allowedMissingInputs; this.extraSkyFunctions = extraSkyFunctions; this.extraPrecomputedValues = extraPrecomputedValues; this.externalFileAction = externalFileAction; this.blacklistedPackagePrefixesFile = blacklistedPackagePrefixesFile; this.binTools = binTools; this.ruleClassProvider = pkgFactory.getRuleClassProvider(); this.skyframeBuildView = new SkyframeBuildView( directories, this, (ConfiguredRuleClassProvider) ruleClassProvider); this.artifactFactory.set(skyframeBuildView.getArtifactFactory()); this.externalFilesHelper = new ExternalFilesHelper( pkgLocator, this.externalFileAction, directories); this.crossRepositoryLabelViolationStrategy = crossRepositoryLabelViolationStrategy; this.buildFilesByPriority = buildFilesByPriority; this.actionOnIOExceptionReadingBuildFile = actionOnIOExceptionReadingBuildFile; this.removeActionsAfterEvaluation.set(false); } private ImmutableMap skyFunctions( PackageFactory pkgFactory, Predicate allowedMissingInputs) { ConfiguredRuleClassProvider ruleClassProvider = (ConfiguredRuleClassProvider) pkgFactory.getRuleClassProvider(); // TODO(janakr): use this semaphore to bound memory usage for SkyFunctions besides // ConfiguredTargetFunction that may have a large temporary memory blow-up. Semaphore cpuBoundSemaphore = new Semaphore(ResourceUsage.getAvailableProcessors()); // We use an immutable map builder for the nice side effect that it throws if a duplicate key // is inserted. ImmutableMap.Builder map = ImmutableMap.builder(); map.put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction()); map.put(SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, new ClientEnvironmentFunction(clientEnv)); map.put(SkyFunctions.ACTION_ENVIRONMENT_VARIABLE, new ActionEnvironmentFunction()); map.put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper)); map.put(SkyFunctions.DIRECTORY_LISTING_STATE, new DirectoryListingStateFunction(externalFilesHelper)); map.put(SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS, new FileSymlinkCycleUniquenessFunction()); map.put(SkyFunctions.FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS, new FileSymlinkInfiniteExpansionUniquenessFunction()); map.put(SkyFunctions.FILE, new FileFunction(pkgLocator)); map.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction()); map.put( SkyFunctions.PACKAGE_LOOKUP, new PackageLookupFunction( deletedPackages, crossRepositoryLabelViolationStrategy, buildFilesByPriority)); map.put(SkyFunctions.CONTAINING_PACKAGE_LOOKUP, new ContainingPackageLookupFunction()); map.put(SkyFunctions.AST_FILE_LOOKUP, new ASTFileLookupFunction(ruleClassProvider)); map.put( SkyFunctions.SKYLARK_IMPORTS_LOOKUP, newSkylarkImportLookupFunction(ruleClassProvider, pkgFactory)); map.put(SkyFunctions.GLOB, newGlobFunction()); map.put(SkyFunctions.TARGET_PATTERN, new TargetPatternFunction()); map.put(SkyFunctions.PREPARE_DEPS_OF_PATTERNS, new PrepareDepsOfPatternsFunction()); map.put(SkyFunctions.PREPARE_DEPS_OF_PATTERN, new PrepareDepsOfPatternFunction(pkgLocator)); map.put( SkyFunctions.PREPARE_DEPS_OF_TARGETS_UNDER_DIRECTORY, new PrepareDepsOfTargetsUnderDirectoryFunction(directories)); map.put(SkyFunctions.COLLECT_TARGETS_IN_PACKAGE, new CollectTargetsInPackageFunction()); map.put( SkyFunctions.COLLECT_PACKAGES_UNDER_DIRECTORY, new CollectPackagesUnderDirectoryFunction(directories)); map.put(SkyFunctions.BLACKLISTED_PACKAGE_PREFIXES, new BlacklistedPackagePrefixesFunction()); map.put(SkyFunctions.TESTS_IN_SUITE, new TestsInSuiteFunction()); map.put(SkyFunctions.TEST_SUITE_EXPANSION, new TestSuiteExpansionFunction()); map.put(SkyFunctions.TARGET_PATTERN_PHASE, new TargetPatternPhaseFunction()); map.put(SkyFunctions.RECURSIVE_PKG, new RecursivePkgFunction(directories)); map.put( SkyFunctions.PACKAGE, newPackageFunction( pkgFactory, packageManager, showLoadingProgress, packageFunctionCache, astCache, numPackagesLoaded, ruleClassProvider, packageProgress)); map.put(SkyFunctions.PACKAGE_ERROR, new PackageErrorFunction()); map.put(SkyFunctions.TARGET_MARKER, new TargetMarkerFunction()); map.put(SkyFunctions.TRANSITIVE_TARGET, new TransitiveTargetFunction(ruleClassProvider)); map.put(Label.TRANSITIVE_TRAVERSAL, new TransitiveTraversalFunction()); map.put( SkyFunctions.CONFIGURED_TARGET, new ConfiguredTargetFunction( new BuildViewProvider(), ruleClassProvider, cpuBoundSemaphore, removeActionsAfterEvaluation)); map.put( SkyFunctions.ASPECT, new AspectFunction( new BuildViewProvider(), ruleClassProvider, removeActionsAfterEvaluation)); map.put(SkyFunctions.LOAD_SKYLARK_ASPECT, new ToplevelSkylarkAspectFunction()); map.put(SkyFunctions.POST_CONFIGURED_TARGET, new PostConfiguredTargetFunction(new BuildViewProvider(), ruleClassProvider)); map.put(SkyFunctions.BUILD_CONFIGURATION, new BuildConfigurationFunction(directories, ruleClassProvider)); map.put( SkyFunctions.CONFIGURATION_FRAGMENT, new ConfigurationFragmentFunction(configurationFragments, ruleClassProvider, directories)); map.put(SkyFunctions.WORKSPACE_NAME, new WorkspaceNameFunction()); map.put(SkyFunctions.WORKSPACE_AST, new WorkspaceASTFunction(ruleClassProvider)); map.put( SkyFunctions.WORKSPACE_FILE, new WorkspaceFileFunction(ruleClassProvider, pkgFactory, directories)); map.put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction()); map.put(SkyFunctions.TARGET_COMPLETION, CompletionFunction.targetCompletionFunction(eventBus)); map.put(SkyFunctions.ASPECT_COMPLETION, CompletionFunction.aspectCompletionFunction(eventBus)); map.put(SkyFunctions.TEST_COMPLETION, new TestCompletionFunction()); map.put(SkyFunctions.ARTIFACT, new ArtifactFunction(allowedMissingInputs)); map.put( SkyFunctions.BUILD_INFO_COLLECTION, new BuildInfoCollectionFunction( artifactFactory, buildInfoFactories, removeActionsAfterEvaluation)); map.put(SkyFunctions.BUILD_INFO, new WorkspaceStatusFunction(removeActionsAfterEvaluation)); map.put(SkyFunctions.COVERAGE_REPORT, new CoverageReportFunction(removeActionsAfterEvaluation)); ActionExecutionFunction actionExecutionFunction = new ActionExecutionFunction(skyframeActionExecutor, tsgm); map.put(SkyFunctions.ACTION_EXECUTION, actionExecutionFunction); this.actionExecutionFunction = actionExecutionFunction; map.put(SkyFunctions.RECURSIVE_FILESYSTEM_TRAVERSAL, new RecursiveFilesystemTraversalFunction()); map.put(SkyFunctions.FILESET_ENTRY, new FilesetEntryFunction()); map.put( SkyFunctions.ACTION_TEMPLATE_EXPANSION, new ActionTemplateExpansionFunction(removeActionsAfterEvaluation)); map.put(SkyFunctions.LOCAL_REPOSITORY_LOOKUP, new LocalRepositoryLookupFunction()); map.put(SkyFunctions.REGISTERED_TOOLCHAINS, new RegisteredToolchainsFunction()); map.put(SkyFunctions.TOOLCHAIN_RESOLUTION, new ToolchainResolutionFunction()); map.putAll(extraSkyFunctions); return map.build(); } protected SkyFunction newGlobFunction() { return new GlobFunction(/*alwaysUseDirListing=*/false); } protected PackageFunction newPackageFunction( PackageFactory pkgFactory, PackageManager packageManager, AtomicBoolean showLoadingProgress, Cache> packageFunctionCache, Cache> astCache, AtomicInteger numPackagesLoaded, RuleClassProvider ruleClassProvider, PackageProgressReceiver packageProgress) { return new PackageFunction( pkgFactory, packageManager, showLoadingProgress, packageFunctionCache, astCache, numPackagesLoaded, null, packageProgress, actionOnIOExceptionReadingBuildFile); } protected SkyFunction newSkylarkImportLookupFunction( RuleClassProvider ruleClassProvider, PackageFactory pkgFactory) { return new SkylarkImportLookupFunction(ruleClassProvider, this.pkgFactory); } protected PerBuildSyscallCache newPerBuildSyscallCache(int concurrencyLevel) { return PerBuildSyscallCache.newBuilder().setConcurrencyLevel(concurrencyLevel).build(); } /** * Gets a (possibly cached) syscalls cache, re-initialized each build. * *

We cache the syscalls cache if possible because construction of the cache is surprisingly * expensive, and is on the critical path of null builds. */ protected final PerBuildSyscallCache getPerBuildSyscallCache(int concurrencyLevel) { if (perBuildSyscallCache != null && lastConcurrencyLevel == concurrencyLevel) { perBuildSyscallCache.clear(); return perBuildSyscallCache; } lastConcurrencyLevel = concurrencyLevel; perBuildSyscallCache = newPerBuildSyscallCache(concurrencyLevel); return perBuildSyscallCache; } @ThreadCompatible public void setActive(boolean active) { this.active = active; } protected void checkActive() { Preconditions.checkState(active); } public void configureActionExecutor( ActionInputFileCache fileCache, ActionInputPrefetcher actionInputPrefetcher) { this.skyframeActionExecutor.configure(fileCache, actionInputPrefetcher); } public void dump(boolean summarize, PrintStream out) { memoizingEvaluator.dump(summarize, out); } public abstract void dumpPackages(PrintStream out); public void setOutputService(OutputService outputService) { this.outputService = outputService; } /** Inform this SkyframeExecutor that a new command is starting. */ public void noteCommandStart() {} /** * Notify listeners about changed files, and release any associated memory afterwards. */ public void drainChangedFiles() { incrementalBuildMonitor.alertListeners(getEventBus()); incrementalBuildMonitor = null; } @VisibleForTesting public BuildDriver getDriverForTesting() { return buildDriver; } /** * This method exists only to allow a module to make a top-level Skyframe call during the * transition to making it fully Skyframe-compatible. Do not add additional callers! */ public SkyValue evaluateSkyKeyForExecutionSetup( final ExtendedEventHandler eventHandler, final SkyKey key) throws EnvironmentalExecException, InterruptedException { synchronized (valueLookupLock) { // We evaluate in keepGoing mode because in the case that the graph does not store its // edges, nokeepGoing builds are not allowed, whereas keepGoing builds are always // permitted. EvaluationResult result = buildDriver.evaluate( ImmutableList.of(key), true, ResourceUsage.getAvailableProcessors(), eventHandler); if (!result.hasError()) { return Preconditions.checkNotNull(result.get(key), "%s %s", result, key); } ErrorInfo errorInfo = Preconditions.checkNotNull(result.getError(key), "%s %s", key, result); Throwables.propagateIfPossible(errorInfo.getException(), EnvironmentalExecException.class); if (errorInfo.getException() != null) { throw new IllegalStateException(errorInfo.getException()); } throw new IllegalStateException(errorInfo.toString()); } } @VisibleForTesting public PathFragment getBlacklistedPackagePrefixesFile() { return blacklistedPackagePrefixesFile; } class BuildViewProvider { /** * Returns the current {@link SkyframeBuildView} instance. */ SkyframeBuildView getSkyframeBuildView() { return skyframeBuildView; } } /** * Must be called before the {@link SkyframeExecutor} can be used (should only be called in * factory methods and as an implementation detail of {@link #resetEvaluator}). */ protected void init() { progressReceiver = newSkyframeProgressReceiver(); ImmutableMap skyFunctions = skyFunctions(pkgFactory, allowedMissingInputs); memoizingEvaluator = evaluatorSupplier.create( skyFunctions, evaluatorDiffer(), progressReceiver, emittedEventState, hasIncrementalState()); buildDriver = getBuildDriver(); } protected SkyframeProgressReceiver newSkyframeProgressReceiver() { return new SkyframeProgressReceiver(); } /** * Reinitializes the Skyframe evaluator, dropping all previously computed values. * *

Be careful with this method as it also deletes all injected values. You need to make sure * that any necessary precomputed values are reinjected before the next build. Constants can be * put in {@link #reinjectConstantValuesLazily}. */ public void resetEvaluator() { init(); emittedEventState.clear(); skyframeBuildView.clearLegacyData(); reinjectConstantValuesLazily(); } protected abstract Differencer evaluatorDiffer(); protected abstract BuildDriver getBuildDriver(); /** * Values whose values are known at startup and guaranteed constant are still wiped from the * evaluator when we create a new one, so they must be re-injected each time we create a new * evaluator. */ private void reinjectConstantValuesLazily() { needToInjectEmbeddedArtifacts = true; needToInjectPrecomputedValuesForAnalysis = true; } /** * Deletes all ConfiguredTarget values from the Skyframe cache. This is done to save memory (e.g. * on a configuration change); since the configuration is part of the key, these key/value pairs * will be sitting around doing nothing until the configuration changes back to the previous * value. * *

The next evaluation will delete all invalid values. */ public abstract void dropConfiguredTargets(); /** * Removes ConfigurationFragmentValues from the cache. */ @VisibleForTesting public void invalidateConfigurationCollection() { invalidate(SkyFunctionName.functionIsIn(ImmutableSet.of(SkyFunctions.CONFIGURATION_FRAGMENT))); } /** * Decides if graph edges should be stored for this build. If not, re-creates the graph to not * store graph edges. Necessary conditions to not store graph edges are: * *

    *
  1. batch (since incremental builds are not possible); *
  2. keep-going (since otherwise bubbling errors up may require edges of done nodes); *
  3. discard_analysis_cache (since otherwise user isn't concerned about saving memory this * way). *
*/ public void decideKeepIncrementalState(boolean batch, Options viewOptions) { // Assume incrementality. } public boolean hasIncrementalState() { return true; } @VisibleForTesting protected abstract Injectable injectable(); /** * Saves memory by clearing analysis objects from Skyframe. If using legacy execution, actually * deletes the relevant values. If using Skyframe execution, clears their data without deleting * them (they will be deleted on the next build). */ public abstract void clearAnalysisCache( Collection topLevelTargets, Collection topLevelAspects); /** * Injects the contents of the computed tools/defaults package. */ @VisibleForTesting public void setupDefaultPackage(String defaultsPackageContents) { PrecomputedValue.DEFAULTS_PACKAGE_CONTENTS.set(injectable(), defaultsPackageContents); } public void injectWorkspaceStatusData(String workspaceName) { PrecomputedValue.WORKSPACE_STATUS_KEY.set(injectable(), workspaceStatusActionFactory.createWorkspaceStatusAction( artifactFactory.get(), WorkspaceStatusValue.ARTIFACT_OWNER, buildId, workspaceName)); } public void injectCoverageReportData(ImmutableList actions) { PrecomputedValue.COVERAGE_REPORT_KEY.set(injectable(), actions); } private void setDefaultVisibility(RuleVisibility defaultVisibility) { PrecomputedValue.DEFAULT_VISIBILITY.set(injectable(), defaultVisibility); } private void setSkylarkSemantics(SkylarkSemanticsOptions skylarkSemanticsOptions) { PrecomputedValue.SKYLARK_SEMANTICS.set(injectable(), skylarkSemanticsOptions); } protected void maybeInjectPrecomputedValuesForAnalysis() { if (needToInjectPrecomputedValuesForAnalysis) { injectExtraPrecomputedValues(extraPrecomputedValues); needToInjectPrecomputedValuesForAnalysis = false; } } public void injectExtraPrecomputedValues( List extraPrecomputedValues) { for (PrecomputedValue.Injected injected : extraPrecomputedValues) { injected.inject(injectable()); } } protected Cache> newPkgFunctionCache() { return CacheBuilder.newBuilder().build(); } protected Cache> newAstCache() { return CacheBuilder.newBuilder().build(); } public ImmutableMap getBuildInfoFactories() { return buildInfoFactories; } private void setShowLoadingProgress(boolean showLoadingProgressValue) { showLoadingProgress.set(showLoadingProgressValue); } @VisibleForTesting public void setCommandId(UUID commandId) { PrecomputedValue.BUILD_ID.set(injectable(), commandId); buildId.set(commandId); } /** Returns the build-info.txt and build-changelist.txt artifacts. */ public Collection getWorkspaceStatusArtifacts(ExtendedEventHandler eventHandler) throws InterruptedException { // Should already be present, unless the user didn't request any targets for analysis. EvaluationResult result = buildDriver.evaluate( ImmutableList.of(WorkspaceStatusValue.SKY_KEY), /*keepGoing=*/true, /*numThreads=*/1, eventHandler); WorkspaceStatusValue value = Preconditions.checkNotNull(result.get(WorkspaceStatusValue.SKY_KEY)); return ImmutableList.of(value.getStableArtifact(), value.getVolatileArtifact()); } public Map getArtifactRootsForFiles( final ExtendedEventHandler eventHandler, Iterable execPaths) throws InterruptedException { return getArtifactRoots(eventHandler, execPaths, true); } public Map getArtifactRoots( final ExtendedEventHandler eventHandler, Iterable execPaths) throws InterruptedException { return getArtifactRoots(eventHandler, execPaths, false); } private Map getArtifactRoots( final ExtendedEventHandler eventHandler, Iterable execPaths, boolean forFiles) throws InterruptedException { final Map packageKeys = new HashMap<>(); for (PathFragment execPath : execPaths) { try { PackageIdentifier pkgIdentifier = PackageIdentifier.discoverFromExecPath(execPath, forFiles); packageKeys.put(execPath, ContainingPackageLookupValue.key(pkgIdentifier)); } catch (LabelSyntaxException e) { continue; } } EvaluationResult result; synchronized (valueLookupLock) { result = buildDriver.evaluate( packageKeys.values(), /*keepGoing=*/ true, /*numThreads=*/ 1, eventHandler); } if (result.hasError()) { return new HashMap<>(); } Map roots = new HashMap<>(); for (PathFragment execPath : execPaths) { ContainingPackageLookupValue value = result.get(packageKeys.get(execPath)); if (value.hasContainingPackage()) { roots.put(execPath, Root.computeSourceRoot( value.getContainingPackageRoot(), value.getContainingPackageName().getRepository())); } else { roots.put(execPath, null); } } return roots; } @VisibleForTesting public WorkspaceStatusAction getLastWorkspaceStatusActionForTesting() { PrecomputedValue value = (PrecomputedValue) buildDriver.getGraphForTesting() .getExistingValueForTesting(PrecomputedValue.WORKSPACE_STATUS_KEY.getKeyForTesting()); return (WorkspaceStatusAction) value.get(); } @VisibleForTesting public ToolchainContext getToolchainContextForTesting( Set