Skip to content

Commit 34b3b43

Browse files
bazel-iofmeum
andauthored
[8.4.0] Skip strategies incompatible with path mapping during resolution (bazelbuild#26563)
Spawn strategies that aren't sandboxed are now skipped while resolving a strategy for a path mapped spawn, which allows non-sandboxed strategies to be listed first and also results in a better error message if no compatible strategy is available (instead of an obscure exec failure). Worker execution is special in that it can always sandbox if needed, but may not do so based on options. For this purpose, path mapped spawns are now treated just like dynamically executed spawns by forcing sandboxing. In the future, the same mechanism can potentially be used to run spawns for rewound actions in Bazel, which must not delete or override their previous outputs. Work towards bazelbuild#22658 (comment) Fixes bazel-contrib/rules_go#4366 Closes bazelbuild#25430. PiperOrigin-RevId: 784040555 Change-Id: I26e110801ce84c41aef5f3e03e34879c595ebedf Commit bazelbuild@a42c981 Co-authored-by: Fabian Meumertzheim <[email protected]>
1 parent 9732c16 commit 34b3b43

File tree

7 files changed

+51
-21
lines changed

7 files changed

+51
-21
lines changed

src/main/java/com/google/devtools/build/lib/actions/Spawns.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ public static boolean mayBeSandboxed(Spawn spawn) {
6767
&& !spawn.getExecutionInfo().containsKey(ExecutionRequirements.LOCAL);
6868
}
6969

70+
/**
71+
* Returns whether a Spawn must be executed on a separate exec root (i.e., in a sandbox) since it
72+
* references rewritten input and output paths.
73+
*/
74+
public static boolean usesPathMapping(Spawn spawn) {
75+
return !spawn.getPathMapper().isNoop();
76+
}
77+
7078
/** Returns whether a Spawn needs network access in order to run successfully. */
7179
public static boolean requiresNetwork(Spawn spawn, boolean defaultSandboxDisallowNetwork) {
7280
if (spawn.getExecutionInfo().containsKey(ExecutionRequirements.BLOCK_NETWORK)) {

src/main/java/com/google/devtools/build/lib/exec/SpawnStrategyResolver.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.devtools.build.lib.actions.Spawn;
2222
import com.google.devtools.build.lib.actions.SpawnResult;
2323
import com.google.devtools.build.lib.actions.SpawnStrategy;
24+
import com.google.devtools.build.lib.actions.Spawns;
2425
import com.google.devtools.build.lib.actions.UserExecException;
2526
import com.google.devtools.build.lib.server.FailureDetails;
2627
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
@@ -86,11 +87,15 @@ public List<? extends SpawnStrategy> resolve(
8687
if (fallbackStrategies.isEmpty()) {
8788
String message =
8889
String.format(
89-
"%s spawn cannot be executed with any of the available strategies: %s. Your"
90+
"%s spawn%s cannot be executed with any of the available strategies: %s. Your"
9091
+ " --spawn_strategy, --genrule_strategy and/or --strategy flags are probably"
9192
+ " too strict. Visit https://github.com/bazelbuild/bazel/issues/7480 for"
9293
+ " advice",
93-
spawn.getMnemonic(), strategies);
94+
spawn.getMnemonic(),
95+
Spawns.usesPathMapping(spawn)
96+
? ", which requires sandboxing due to path mapping,"
97+
: "",
98+
strategies);
9499
throw new UserExecException(
95100
FailureDetail.newBuilder()
96101
.setMessage(message)

src/main/java/com/google/devtools/build/lib/exec/local/LocalSpawnRunner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public SpawnResult exec(Spawn spawn, SpawnExecutionContext context)
170170

171171
@Override
172172
public boolean canExec(Spawn spawn) {
173-
return true;
173+
return !Spawns.usesPathMapping(spawn);
174174
}
175175

176176
@Override

src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.devtools.build.lib.actions.ForbiddenActionInputException;
2727
import com.google.devtools.build.lib.actions.Spawn;
2828
import com.google.devtools.build.lib.actions.SpawnResult;
29+
import com.google.devtools.build.lib.actions.Spawns;
2930
import com.google.devtools.build.lib.events.Event;
3031
import com.google.devtools.build.lib.events.ExtendedEventHandler;
3132
import com.google.devtools.build.lib.exec.ExecutionOptions;
@@ -489,6 +490,9 @@ public boolean canExec(Spawn spawn) {
489490

490491
@Override
491492
public boolean canExecWithLegacyFallback(Spawn spawn) {
493+
if (Spawns.usesPathMapping(spawn)) {
494+
return false;
495+
}
492496
boolean canExec = !sandboxSpawnRunner.canExec(spawn) && fallbackSpawnRunner.canExec(spawn);
493497
if (canExec) {
494498
// We give a warning to use strategies instead, whether or not we allow the fallback

src/main/java/com/google/devtools/build/lib/worker/WorkerParser.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,21 @@ static WorkerKey createWorkerKey(
132132
boolean dynamic,
133133
WorkerProtocolFormat protocolFormat) {
134134
String workerKeyMnemonic = Spawns.getWorkerKeyMnemonic(spawn);
135-
boolean multiplex = options.workerMultiplex && Spawns.supportsMultiplexWorkers(spawn);
136-
if (dynamic && !(Spawns.supportsMultiplexSandboxing(spawn) && options.multiplexSandboxing)) {
137-
multiplex = false;
138-
}
135+
boolean mustSandbox = dynamic || Spawns.usesPathMapping(spawn);
136+
boolean shouldMultiplex = options.workerMultiplex && Spawns.supportsMultiplexWorkers(spawn);
137+
boolean canSandboxMultiplex =
138+
options.multiplexSandboxing && Spawns.supportsMultiplexSandboxing(spawn);
139139
boolean sandboxed;
140-
if (multiplex) {
141-
sandboxed =
142-
Spawns.supportsMultiplexSandboxing(spawn) && (options.multiplexSandboxing || dynamic);
140+
boolean multiplex;
141+
if (mustSandbox) {
142+
sandboxed = true;
143+
multiplex = shouldMultiplex && canSandboxMultiplex;
144+
} else if (shouldMultiplex) {
145+
sandboxed = canSandboxMultiplex;
146+
multiplex = true;
143147
} else {
144-
sandboxed = options.workerSandboxing || dynamic;
148+
sandboxed = options.workerSandboxing;
149+
multiplex = false;
145150
}
146151
boolean useInMemoryTracking = false;
147152
if (sandboxed) {

src/test/java/com/google/devtools/build/lib/worker/WorkerSpawnRunnerTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.google.devtools.build.lib.actions.ExecutionRequirements;
4141
import com.google.devtools.build.lib.actions.ExecutionRequirements.WorkerProtocolFormat;
4242
import com.google.devtools.build.lib.actions.InputMetadataProvider;
43+
import com.google.devtools.build.lib.actions.PathMapper;
4344
import com.google.devtools.build.lib.actions.ResourceManager;
4445
import com.google.devtools.build.lib.actions.ResourceSet;
4546
import com.google.devtools.build.lib.actions.Spawn;
@@ -106,6 +107,7 @@ public void setUp() throws Exception {
106107
.registerWorker(
107108
anyInt(), anyLong(), any(), anyString(), anyBoolean(), anyBoolean(), anyInt(), any());
108109
when(spawn.getLocalResources()).thenReturn(ResourceSet.createWithRamCpu(100, 1));
110+
when(spawn.getPathMapper()).thenReturn(PathMapper.NOOP);
109111
when(resourceManager.acquireResources(any(), any(), any())).thenReturn(resourceHandle);
110112
when(resourceHandle.getWorker()).thenReturn(worker);
111113
}

src/test/shell/bazel/path_mapping_test.sh

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ function tear_down() {
9393
stop_worker
9494
}
9595

96+
function test_path_stripping_local_fails() {
97+
cache_dir=$(mktemp -d)
98+
99+
bazel build -c fastbuild \
100+
--disk_cache=$cache_dir \
101+
--experimental_output_paths=strip \
102+
--strategy=Javac=local \
103+
//src/main/java/com/example:Main &> $TEST_log && fail "build succeeded unexpectedly"
104+
expect_log 'Javac spawn, which requires sandboxing due to path mapping, cannot be executed with any of the available strategies'
105+
}
106+
96107
function test_path_stripping_sandboxed() {
97108
if is_windows; then
98109
echo "Skipping test_path_stripping_sandboxed on Windows as it requires sandboxing"
@@ -101,10 +112,12 @@ function test_path_stripping_sandboxed() {
101112

102113
cache_dir=$(mktemp -d)
103114

115+
# Validate that the sandboxed strategy is preferred over the local strategy
116+
# with path mapping.
104117
bazel run -c fastbuild \
105118
--disk_cache=$cache_dir \
106119
--experimental_output_paths=strip \
107-
--strategy=Javac=sandboxed \
120+
--strategy=Javac=local,sandboxed \
108121
//src/main/java/com/example:Main &> $TEST_log || fail "run failed unexpectedly"
109122
expect_log 'Hello, World!'
110123
# JavaToolchainCompileBootClasspath, JavaToolchainCompileClasses, 1x header compilation and 2x
@@ -123,19 +136,14 @@ function test_path_stripping_sandboxed() {
123136
}
124137

125138
function test_path_stripping_singleplex_worker() {
126-
if is_windows; then
127-
echo "Skipping test_path_stripping_singleplex_worker on Windows as it requires sandboxing"
128-
return
129-
fi
130-
131139
cache_dir=$(mktemp -d)
132140

141+
# Worker sandboxing is enabled automatically, multiplexing is disabled since
142+
# the default toolchain does not support sandboxing yet.
133143
bazel run -c fastbuild \
134144
--disk_cache=$cache_dir \
135145
--experimental_output_paths=strip \
136146
--strategy=Javac=worker \
137-
--worker_sandboxing \
138-
--noexperimental_worker_multiplex \
139147
//src/main/java/com/example:Main &> $TEST_log || fail "run failed unexpectedly"
140148
expect_log 'Hello, World!'
141149
# JavaToolchainCompileBootClasspath, JavaToolchainCompileClasses and header compilation.
@@ -148,8 +156,6 @@ function test_path_stripping_singleplex_worker() {
148156
--disk_cache=$cache_dir \
149157
--experimental_output_paths=strip \
150158
--strategy=Javac=worker \
151-
--worker_sandboxing \
152-
--noexperimental_worker_multiplex \
153159
//src/main/java/com/example:Main &> $TEST_log || fail "run failed unexpectedly"
154160
expect_log 'Hello, World!'
155161
expect_log '5 disk cache hit'

0 commit comments

Comments
 (0)