Skip to content

Commit 0c74741

Browse files
Remote: Postpone the block waiting in afterCommand to BlockWaitingModule (bazelbuild#14833)
When implementing async upload, we introduced a block waiting behaviour in `RemoteModule#afterCommand` so that uploads happened in the background can be waited before the whole build complete. However, there are other block waiting code in other module's `afterCommand` method (e.g. BES module). Block waiting in remote module will prevent other modules' `afterCommand` from executing until it's completed. This causes issues like bazelbuild#14576. This PR adds a new module `BlockWaitingModule` whose sole purpose is to accept tasks submitted by other modules in `afterCommand` and block waiting all the tasks in its own `afterCommand` method. So those tasks can be executed in parallel. This PR only updates RemoteModule's `afterCommand` method to submit block waiting task. Other modules should be updated to use `BlockWaitingModule` as well but that's beyond the scope this this PR. This PR along with 73a76a8 fix bazelbuild#14576. Closes bazelbuild#14618. PiperOrigin-RevId: 424295121 (cherry picked from commit 621649d) Co-authored-by: Chi Wang <[email protected]>
1 parent 344e8f8 commit 0c74741

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

src/main/java/com/google/devtools/build/lib/bazel/Bazel.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ public final class Bazel {
7676
com.google.devtools.build.lib.metrics.PostGCMemoryUseRecorder.GcAfterBuildModule.class,
7777
com.google.devtools.build.lib.packages.metrics.PackageMetricsModule.class,
7878
com.google.devtools.build.lib.metrics.MetricsModule.class,
79-
BazelBuiltinCommandModule.class);
79+
BazelBuiltinCommandModule.class,
80+
// This module needs to be registered after any module submitting tasks with its {@code
81+
// submit} method.
82+
com.google.devtools.build.lib.runtime.BlockWaitingModule.class);
8083

8184
public static void main(String[] args) {
8285
BlazeVersionInfo.setBuildInfo(tryGetBuildInfo());

src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.google.devtools.build.lib.remote.common.RemotePathResolver.SiblingRepositoryLayoutResolver;
3232
import com.google.devtools.build.lib.remote.options.RemoteOptions;
3333
import com.google.devtools.build.lib.remote.util.DigestUtil;
34+
import com.google.devtools.build.lib.runtime.BlockWaitingModule;
3435
import com.google.devtools.build.lib.runtime.CommandEnvironment;
3536
import com.google.devtools.build.lib.vfs.Path;
3637
import java.util.concurrent.Executor;
@@ -211,7 +212,9 @@ void setFilesToDownload(ImmutableSet<ActionInput> topLevelOutputs) {
211212

212213
public void afterCommand() {
213214
if (remoteExecutionService != null) {
214-
remoteExecutionService.shutdown();
215+
BlockWaitingModule blockWaitingModule =
216+
checkNotNull(env.getRuntime().getBlazeModule(BlockWaitingModule.class));
217+
blockWaitingModule.submit(() -> remoteExecutionService.shutdown());
215218
} else {
216219
if (remoteCache != null) {
217220
remoteCache.release();
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2022 The Bazel Authors. All rights reserved.
2+
//
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.
14+
package com.google.devtools.build.lib.runtime;
15+
16+
import static com.google.common.base.Preconditions.checkNotNull;
17+
import static com.google.common.base.Preconditions.checkState;
18+
import static java.util.concurrent.TimeUnit.SECONDS;
19+
20+
import com.google.common.util.concurrent.ThreadFactoryBuilder;
21+
import com.google.devtools.build.lib.util.AbruptExitException;
22+
import java.util.concurrent.ExecutorService;
23+
import java.util.concurrent.Executors;
24+
import javax.annotation.Nullable;
25+
26+
/** A {@link BlazeModule} that waits for submitted tasks to terminate after every command. */
27+
public class BlockWaitingModule extends BlazeModule {
28+
@Nullable private ExecutorService executorService;
29+
30+
@Override
31+
public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
32+
checkState(executorService == null, "executorService must be null");
33+
34+
executorService =
35+
Executors.newCachedThreadPool(
36+
new ThreadFactoryBuilder().setNameFormat("block-waiting-%d").build());
37+
}
38+
39+
@SuppressWarnings("FutureReturnValueIgnored")
40+
public void submit(Runnable task) {
41+
checkNotNull(executorService, "executorService must not be null");
42+
43+
executorService.submit(task);
44+
}
45+
46+
@Override
47+
public void afterCommand() throws AbruptExitException {
48+
checkNotNull(executorService, "executorService must not be null");
49+
50+
executorService.shutdown();
51+
try {
52+
executorService.awaitTermination(Long.MAX_VALUE, SECONDS);
53+
} catch (InterruptedException e) {
54+
Thread.currentThread().interrupt();
55+
}
56+
57+
executorService = null;
58+
}
59+
}

0 commit comments

Comments
 (0)