Skip to content

Commit

Permalink
Run idle server GC immediately following a `--nokeep_state_after_buil…
Browse files Browse the repository at this point in the history
…d_command` instead of waiting 10 seconds.

This helps to ensure that weakly reachable objects are not resurrected. Using the idle server task avoids blocking command completion on a full GC, which can take multiple seconds.

PiperOrigin-RevId: 550056326
Change-Id: Ia55a2360a196ee0f0dcbb0ac6b6baa11e39e244d
  • Loading branch information
justinhorvitz authored and copybara-github committed Jul 21, 2023
1 parent f4b01b1 commit f6344ff
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,24 @@ public final class BlazeCommandResult {
@Nullable private final ExecRequest execDescription;
private final ImmutableList<Any> responseExtensions;
private final boolean shutdown;
private final boolean stateKeptAfterBuild;

private BlazeCommandResult(
DetailedExitCode detailedExitCode,
@Nullable ExecRequest execDescription,
boolean shutdown,
ImmutableList<Any> responseExtensions) {
ImmutableList<Any> responseExtensions,
boolean stateKeptAfterBuild) {
this.detailedExitCode = Preconditions.checkNotNull(detailedExitCode);
this.execDescription = execDescription;
this.shutdown = shutdown;
this.responseExtensions = responseExtensions;
this.stateKeptAfterBuild = stateKeptAfterBuild;
}

private BlazeCommandResult(
DetailedExitCode detailedExitCode, @Nullable ExecRequest execDescription, boolean shutdown) {
this(detailedExitCode, execDescription, shutdown, ImmutableList.of());
this(detailedExitCode, execDescription, shutdown, ImmutableList.of(), true);
}

public ExitCode getExitCode() {
Expand Down Expand Up @@ -85,13 +88,20 @@ public ImmutableList<Any> getResponseExtensions() {
return responseExtensions;
}

/** Reflects the value of {@link CommonCommandOptions#keepStateAfterBuild}. */
public boolean stateKeptAfterBuild() {
return stateKeptAfterBuild;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("exitCode", getExitCode())
.add("failureDetail", getFailureDetail())
.add("execDescription", execDescription)
.add("shutdown", shutdown)
.add("responseExtensions", responseExtensions)
.add("stateKeptAfterBuild", stateKeptAfterBuild)
.toString();
}

Expand All @@ -116,9 +126,15 @@ public static BlazeCommandResult detailedExitCode(DetailedExitCode detailedExitC
}

public static BlazeCommandResult withResponseExtensions(
BlazeCommandResult result, ImmutableList<Any> responseExtensions) {
BlazeCommandResult result,
ImmutableList<Any> responseExtensions,
boolean stateKeptAfterBuild) {
return new BlazeCommandResult(
result.detailedExitCode, result.execDescription, result.shutdown, responseExtensions);
result.detailedExitCode,
result.execDescription,
result.shutdown,
responseExtensions,
stateKeptAfterBuild);
}

public static BlazeCommandResult execute(ExecRequest execDescription) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ public BlazeCommandResult afterCommand(CommandEnvironment env, BlazeCommandResul
DebugLoggerConfigurator.flushServerLog();
storedExitCode.set(null);
return BlazeCommandResult.withResponseExtensions(
finalCommandResult, env.getResponseExtensions());
finalCommandResult, env.getResponseExtensions(), commonOptions.keepStateAfterBuild);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.GoogleLogger;
import com.google.devtools.build.lib.server.CommandProtos.CancelRequest;
import com.google.devtools.build.lib.server.IdleServerTasks.IdleServerCleanupStrategy;
import com.google.devtools.build.lib.util.ThreadUtils;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -43,7 +44,7 @@ class CommandManager {
CommandManager(boolean doIdleServerTasks, @Nullable String slowInterruptMessageSuffix) {
this.doIdleServerTasks = doIdleServerTasks;
this.slowInterruptMessageSuffix = slowInterruptMessageSuffix;
idle();
idle(IdleServerCleanupStrategy.DELAYED);
}

void preemptEligibleCommands() {
Expand Down Expand Up @@ -132,11 +133,11 @@ private void registerCommand(RunningCommand command) {
logger.atInfo().log("Starting command %s on thread %s", command.id, command.thread.getName());
}

private void idle() {
private void idle(IdleServerCleanupStrategy cleanupStrategy) {
Preconditions.checkState(idleServerTasks == null);
if (doIdleServerTasks) {
idleServerTasks = new IdleServerTasks();
idleServerTasks.idle();
idleServerTasks.idle(cleanupStrategy);
}
}

Expand Down Expand Up @@ -176,10 +177,11 @@ private void startSlowInterruptWatcher(final ImmutableSet<String> commandIds) {
interruptWatcherThread.start();
}

class RunningCommand implements AutoCloseable {
final class RunningCommand implements AutoCloseable {
private final Thread thread;
private final String id;
private final boolean preemptible;
private IdleServerCleanupStrategy cleanupStrategy = IdleServerCleanupStrategy.DELAYED;

private RunningCommand(boolean preemptible) {
thread = Thread.currentThread();
Expand All @@ -192,7 +194,7 @@ public void close() {
synchronized (runningCommandsMap) {
runningCommandsMap.remove(id);
if (runningCommandsMap.isEmpty()) {
idle();
idle(cleanupStrategy);
}
runningCommandsMap.notify();
}
Expand All @@ -205,7 +207,12 @@ String getId() {
}

boolean isPreemptible() {
return this.preemptible;
return preemptible;
}

/** Requests a manual GC as soon as the server becomes idle. */
void requestEagerIdleServerCleanup() {
cleanupStrategy = IdleServerCleanupStrategy.EAGER;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,13 @@ private void executeCommand(RunRequest request, BlockingStreamObserver<RunRespon
.setCode(Command.Code.INVOCATION_POLICY_PARSE_FAILURE))
.build()));
}
if (!result.stateKeptAfterBuild()) {
// If state was not kept, GC as soon as the server becomes idle. This ensures that weakly
// reachable objects are not "resurrected" on a subsequent command. See b/291641466. Without
// this call, a manual GC will only be triggered if the server remains idle for at least 10
// seconds before the next command starts.
command.requestEagerIdleServerCleanup();
}
} catch (InterruptedException e) {
result =
BlazeCommandResult.detailedExitCode(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,35 @@
import java.util.concurrent.TimeUnit;

/**
* Run cleanup-related tasks during idle periods in the server.
* idle() and busy() must be called in that order, and only once.
* Run cleanup-related tasks during idle periods in the server. idle() and busy() must be called in
* that order, and only once.
*/
class IdleServerTasks {
private final ScheduledThreadPoolExecutor executor;
final class IdleServerTasks {

private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();

enum IdleServerCleanupStrategy {
EAGER(0),
DELAYED(10);

private final long delaySeconds;

IdleServerCleanupStrategy(long delaySeconds) {
this.delaySeconds = delaySeconds;
}
}

private final ScheduledThreadPoolExecutor executor;

/** Must be called from the main thread. */
public IdleServerTasks() {
this.executor = new ScheduledThreadPoolExecutor(
1,
new ThreadFactoryBuilder().setNameFormat("idle-server-tasks-%d").build());
this.executor =
new ScheduledThreadPoolExecutor(
1, new ThreadFactoryBuilder().setNameFormat("idle-server-tasks-%d").build());
}

/**
* Called when the server becomes idle. Should not block, but may invoke
* new threads.
*/
public void idle() {
/** Called when the server becomes idle. Should not block, but may invoke new threads. */
public void idle(IdleServerCleanupStrategy cleanupStrategy) {
Preconditions.checkState(!executor.isShutdown());

@SuppressWarnings("unused")
Expand All @@ -66,7 +76,7 @@ public void idle() {
StringUtilities.prettyPrintBytes(before.getCommitted()),
StringUtilities.prettyPrintBytes(after.getCommitted()));
},
10,
cleanupStrategy.delaySeconds,
TimeUnit.SECONDS);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ public BlazeCommandResult exec(
BlazeCommandResult.success(),
ImmutableList.of(
Any.pack(StringValue.of("foo")),
Any.pack(BytesValue.of(ByteString.copyFromUtf8("bar")))));
Any.pack(BytesValue.of(ByteString.copyFromUtf8("bar")))),
true);
}
};
createServer(dispatcher);
Expand Down

0 comments on commit f6344ff

Please sign in to comment.