Skip to content

Commit

Permalink
feat: add option to exit early if analysis cache is discarded
Browse files Browse the repository at this point in the history
  • Loading branch information
mattem committed Mar 25, 2023
1 parent 130703a commit cd08c0a
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ public class AnalysisOptions extends OptionsBase {
)
public boolean discardAnalysisCache;

@Option(
name = "fail_on_analysis_cache_discard",
defaultValue = "false",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.EAGERNESS_TO_EXIT},
help = "If discarding the analysis cache due to a change in the build system, setting this option will cause bazel" +
" to exit, rather than continuing with the build. This option has no affect when 'discard_analysis_cache'" +
" is also set."
)
public boolean failOnAnalysisCacheDiscard;

@Option(
name = "max_config_changes_to_show",
defaultValue = "3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,10 @@
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.TargetPatterns;
import com.google.devtools.build.lib.server.FailureDetails.TargetPatterns.Code;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator;
import com.google.devtools.build.lib.skyframe.*;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator.TopLevelAspectsKey;
import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
import com.google.devtools.build.lib.skyframe.BuildResultListener;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
import com.google.devtools.build.lib.skyframe.CoverageReportValue;
import com.google.devtools.build.lib.skyframe.RepositoryMappingValue.RepositoryMappingResolutionException;
import com.google.devtools.build.lib.skyframe.SkyframeAnalysisAndExecutionResult;
import com.google.devtools.build.lib.skyframe.SkyframeAnalysisResult;
import com.google.devtools.build.lib.skyframe.SkyframeBuildView;
import com.google.devtools.build.lib.skyframe.SkyframeBuildView.BuildDriverKeyTestContext;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.RegexFilter;
Expand Down Expand Up @@ -223,14 +213,9 @@ public AnalysisResult update(
@Nullable ResourceManager resourceManager,
@Nullable BuildResultListener buildResultListener,
@Nullable ExecutionSetup executionSetupCallback,
@Nullable BuildConfigurationsCreated buildConfigurationsCreatedCallback,
@Nullable BuildDriverKeyTestContext buildDriverKeyTestContext)
throws ViewCreationFailedException,
InvalidConfigurationException,
InterruptedException,
BuildFailedException,
TestExecException,
AbruptExitException {
@Nullable BuildConfigurationsCreated buildConfigurationsCreatedCallback)
throws ViewCreationFailedException, InvalidConfigurationException, InterruptedException,
BuildFailedException, TestExecException, AbruptExitException, AnalysisCacheDiscardedException {
logger.atInfo().log("Starting analysis");
pollInterruptedStatus();

Expand Down Expand Up @@ -268,8 +253,8 @@ public AnalysisResult update(
skyframeExecutor);
}

skyframeBuildView.setConfiguration(
eventHandler, configuration, viewOptions.maxConfigChangesToShow);
skyframeBuildView.setConfigurations(
eventHandler, configurations, viewOptions.maxConfigChangesToShow, viewOptions.failOnAnalysisCacheDiscard);

eventBus.post(new MakeEnvironmentEvent(configuration.getMakeEnvironment()));
eventBus.post(configuration.toBuildEvent());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,8 @@
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.BuildInfoCollectionFunction;
import com.google.devtools.build.lib.skyframe.BuildResultListener;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
import com.google.devtools.build.lib.skyframe.*;
import com.google.devtools.build.lib.skyframe.RepositoryMappingValue.RepositoryMappingResolutionException;
import com.google.devtools.build.lib.skyframe.SkyframeBuildView.BuildDriverKeyTestContext;
import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue;
import com.google.devtools.build.lib.skyframe.TopLevelStatusEvents.TopLevelTargetAnalyzedEvent;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.DetailedExitCode;
Expand Down Expand Up @@ -79,15 +75,11 @@ static AnalysisAndExecutionResult execute(
BuildOptions buildOptions,
TargetPatternPhaseValue loadingResult,
ExecutionSetup executionSetupCallback,
BuildConfigurationsCreated buildConfigurationCreatedCallback,
BuildDriverKeyTestContext buildDriverKeyTestContext)
throws BuildFailedException,
InterruptedException,
ViewCreationFailedException,
AbruptExitException,
InvalidConfigurationException,
TestExecException,
RepositoryMappingResolutionException {
BuildConfigurationsCreated buildConfigurationCreatedCallback)
throws BuildFailedException, InterruptedException, ViewCreationFailedException,
TargetParsingException, LoadingFailedException, AbruptExitException,
InvalidConfigurationException, TestExecException, RepositoryMappingResolutionException,
AnalysisCacheDiscardedException {

// Compute the heuristic instrumentation filter if needed.
if (request.needsInstrumentationFilter()) {
Expand Down Expand Up @@ -207,15 +199,10 @@ private static AnalysisAndExecutionResult runAnalysisAndExecutionPhase(
TargetPatternPhaseValue loadingResult,
BuildOptions targetOptions,
ExecutionSetup executionSetupCallback,
BuildConfigurationsCreated buildConfigurationCreatedCallback,
BuildDriverKeyTestContext buildDriverKeyTestContext)
throws InterruptedException,
InvalidConfigurationException,
ViewCreationFailedException,
BuildFailedException,
TestExecException,
RepositoryMappingResolutionException,
AbruptExitException {
BuildConfigurationsCreated buildConfigurationCreatedCallback)
throws InterruptedException, InvalidConfigurationException, ViewCreationFailedException,
BuildFailedException, TestExecException, RepositoryMappingResolutionException,
AbruptExitException, AnalysisCacheDiscardedException {
env.getReporter().handle(Event.progress("Loading complete. Analyzing..."));

ImmutableSet<Label> explicitTargetPatterns =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,9 @@
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.*;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
import com.google.devtools.build.lib.skyframe.BuildInfoCollectionFunction;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
import com.google.devtools.build.lib.skyframe.RepositoryMappingValue.RepositoryMappingResolutionException;
import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue;
import com.google.devtools.build.lib.skyframe.TopLevelStatusEvents.AspectAnalyzedEvent;
import com.google.devtools.build.lib.skyframe.TopLevelStatusEvents.TestAnalyzedEvent;
import com.google.devtools.build.lib.skyframe.TopLevelStatusEvents.TopLevelTargetAnalyzedEvent;
Expand Down Expand Up @@ -87,7 +84,7 @@ public static AnalysisResult execute(
TargetValidator validator)
throws BuildFailedException, InterruptedException, ViewCreationFailedException,
TargetParsingException, LoadingFailedException, AbruptExitException,
InvalidConfigurationException, RepositoryMappingResolutionException {
InvalidConfigurationException, RepositoryMappingResolutionException, AnalysisCacheDiscardedException {

// Target pattern evaluation.
TargetPatternPhaseValue loadingResult;
Expand Down Expand Up @@ -219,7 +216,7 @@ private static AnalysisResult runAnalysisPhase(
TargetPatternPhaseValue loadingResult,
BuildOptions targetOptions)
throws InterruptedException, InvalidConfigurationException,
RepositoryMappingResolutionException, ViewCreationFailedException {
RepositoryMappingResolutionException, ViewCreationFailedException, AnalysisCacheDiscardedException {
Stopwatch timer = Stopwatch.createStarted();
env.getReporter().handle(Event.progress("Loading complete. Analyzing..."));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.server.FailureDetails.ActionQuery;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.BuildResultListener;
import com.google.devtools.build.lib.skyframe.AnalysisCacheDiscardedException;
import com.google.devtools.build.lib.skyframe.RepositoryMappingValue.RepositoryMappingResolutionException;
import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutor;
import com.google.devtools.build.lib.skyframe.SkyframeBuildView.BuildDriverKeyTestContext;
Expand Down Expand Up @@ -151,7 +151,7 @@ public void buildTargets(BuildRequest request, BuildResult result, TargetValidat
throws BuildFailedException, InterruptedException, ViewCreationFailedException,
TargetParsingException, LoadingFailedException, AbruptExitException,
InvalidConfigurationException, TestExecException, ExitException,
PostExecutionActionGraphDumpException, RepositoryMappingResolutionException {
PostExecutionActionGraphDumpException, RepositoryMappingResolutionException, AnalysisCacheDiscardedException {
try (SilentCloseable c = Profiler.instance().profile("validateOptions")) {
validateOptions(request);
}
Expand Down Expand Up @@ -311,7 +311,8 @@ private void buildTargetsWithMergedAnalysisExecution(
BuildOptions buildOptions)
throws InterruptedException, TargetParsingException, LoadingFailedException,
AbruptExitException, ViewCreationFailedException, BuildFailedException, TestExecException,
InvalidConfigurationException, RepositoryMappingResolutionException {
InvalidConfigurationException, RepositoryMappingResolutionException, AnalysisCacheDiscardedException {

// Target pattern evaluation.
TargetPatternPhaseValue loadingResult;
Profiler.instance().markPhase(ProfilePhase.TARGET_PATTERN_EVAL);
Expand Down Expand Up @@ -572,7 +573,7 @@ public BuildResult processRequest(
} else {
result.setCatastrophe();
}
} catch (TargetParsingException | LoadingFailedException e) {
} catch (TargetParsingException | LoadingFailedException | AnalysisCacheDiscardedException e) {
detailedExitCode = e.getDetailedExitCode();
reportExceptionError(e);
} catch (RepositoryMappingResolutionException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.google.devtools.build.lib.skyframe;

import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.util.DetailedExitCode;

/**
* An exception thrown when the analysis cache is discarded, and the `fail_on_analysis_cache_discard` option is
* set.
*/
public class AnalysisCacheDiscardedException extends Exception implements DetailedException {
static final String DISCARD_FLAG = "--fail_on_analysis_cache_discard";

public AnalysisCacheDiscardedException(String diff) {
super(String.format("%s, analysis cache would have been discarded and %s is set.", diff, DISCARD_FLAG));
}

@Override
public DetailedExitCode getDetailedExitCode() {
return DetailedExitCode.of(
FailureDetails.FailureDetail
.newBuilder()
.setMessage(this.getMessage())
.setAnalysis(
FailureDetails.Analysis
.newBuilder()
.setCode(
FailureDetails.Analysis.Code.ANALYSIS_CACHE_DISCARDED
).build()
)
.build()
);
}
}
1 change: 1 addition & 0 deletions src/main/java/com/google/devtools/build/lib/skyframe/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ java_library(
"ActionLookupConflictFindingFunction.java",
"ActionLookupValuesTraversal.java",
"ActionOutputDirectoryHelper.java",
"AnalysisCacheDiscardedException.java",
"AspectCompletor.java",
"AspectFunction.java",
"BazelSkyframeExecutorConstants.java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,11 @@ private ImmutableSet<OptionDefinition> getNativeCacheInvalidatingDifferences(

/** Sets the configuration. Not thread-safe. DO NOT CALL except from tests! */
@VisibleForTesting
public void setConfiguration(
EventHandler eventHandler, BuildConfigurationValue configuration, int maxDifferencesToShow) {
public void setConfigurations(
EventHandler eventHandler,
BuildConfigurationCollection configurations,
int maxDifferencesToShow,
boolean failOnAnalysisCacheDiscard) throws AnalysisCacheDiscardedException {
if (skyframeAnalysisWasDiscarded) {
eventHandler.handle(
Event.info(
Expand All @@ -280,6 +283,10 @@ public void setConfiguration(
} else {
String diff = describeConfigurationDifference(configuration, maxDifferencesToShow);
if (diff != null) {
if (failOnAnalysisCacheDiscard) {
throw new AnalysisCacheDiscardedException(diff);
}

eventHandler.handle(Event.info(diff + ", discarding analysis cache."));
// Note that clearing the analysis cache is currently required for correctness. It is also
// helpful to save memory.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ public final class ExitCode {
ExitCode.create(45, "PERSISTENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR");
public static final ExitCode EXTERNAL_DEPS_ERROR = ExitCode.create(48, "EXTERNAL_DEPS_ERROR");

public static final ExitCode ANALYSIS_CACHE_DISCARD_FAILURE =
ExitCode.create(49, "ANALYSIS_CACHE_DISCARD_FAILURE");

/**
* Creates and returns an ExitCode. Requires a unique exit code number.
*
Expand Down
1 change: 1 addition & 0 deletions src/main/protobuf/failure_details.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,7 @@ message Analysis {
CONFIGURED_VALUE_CREATION_FAILED = 18 [(metadata) = { exit_code: 1 }];
INCOMPATIBLE_TARGET_REQUESTED = 19 [(metadata) = { exit_code: 1 }];
ANALYSIS_FAILURE_PROPAGATION_FAILED = 20 [(metadata) = { exit_code: 1 }];
ANALYSIS_CACHE_DISCARDED = 21 [(metadata) = { exit_code: 49 }];
}

Code code = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
Expand All @@ -34,6 +35,7 @@
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.rules.java.JavaInfo;
import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
import com.google.devtools.build.lib.skyframe.AnalysisCacheDiscardedException;
import com.google.devtools.build.lib.testutil.TestConstants.InternalTestExecutionMode;
import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
import com.google.devtools.common.options.Option;
Expand Down Expand Up @@ -1175,4 +1177,16 @@ public void cacheClearMessageAfterDiscardAnalysisCacheBuildWithRelevantOptionCha
assertDoesNotContainEvent("Build option");
assertContainsEvent("discarding analysis cache");
}

@Test
public void throwsIfAnalysisCacheIsDiscardedWhenOptionSet() throws Exception {
setupDiffResetTesting();
scratch.file("test/BUILD", "load(':lib.bzl', 'normal_lib')", "normal_lib(name='top')");
useConfiguration("--definitely_relevant=old");
update("//test:top");
useConfiguration("--fail_on_analysis_cache_discard", "--definitely_relevant=new");

Throwable t = assertThrows(AnalysisCacheDiscardedException.class, () -> update("//test:top"));
assertTrue(t.getMessage().contains("analysis cache would have been discarded"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
import com.google.devtools.build.lib.packages.RawAttributeMapper;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.runtime.QuiescingExecutorsImpl;
import com.google.devtools.build.lib.skyframe.AnalysisCacheDiscardedException;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
Expand Down Expand Up @@ -201,7 +201,7 @@ public AnalysisResult update(
ExtendedEventHandler eventHandler,
EventBus eventBus)
throws ViewCreationFailedException, InterruptedException, InvalidConfigurationException,
BuildFailedException, TestExecException, AbruptExitException {
BuildFailedException, TestExecException, AbruptExitException, AnalysisCacheDiscardedException {
populateActionLookupKeyMapAndGetDiff();
return buildView.update(
loadingResult,
Expand All @@ -227,10 +227,15 @@ public AnalysisResult update(
/* buildDriverKeyTestContext= */ null);
}

/** Sets the configuration. Not thread-safe. */
public void setConfigurationForTesting(
EventHandler eventHandler, BuildConfigurationValue configuration) {
skyframeBuildView.setConfiguration(eventHandler, configuration, /* maxDifferencesToShow= */ -1);
/** Sets the configurations. Not thread-safe. */
public void setConfigurationsForTesting(
EventHandler eventHandler, BuildConfigurationCollection configurations) {
try {
skyframeBuildView.setConfigurations(
eventHandler, configurations, /* maxDifferencesToShow */ -1, /* failOnAnalysisCacheDiscard */ false);
} catch (AnalysisCacheDiscardedException e) {
// Will never throw, as failOnAnalysisCacheDiscard is explicitly set false in the call above.
}
}

public ArtifactFactory getArtifactFactory() {
Expand Down

0 comments on commit cd08c0a

Please sign in to comment.