blob: 0e1d65d628e645a01c392c266ac650f4e83ebd0a [file] [log] [blame]
// Copyright 2023 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.remote;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.FileArtifactValue;
import com.google.devtools.build.lib.actions.cache.ActionCache;
import com.google.devtools.build.lib.skyframe.ActionExecutionValue;
import com.google.devtools.build.lib.skyframe.SkyFunctions;
import com.google.devtools.build.lib.skyframe.TreeArtifactValue;
import com.google.devtools.build.skyframe.MemoizingEvaluator;
import java.util.Set;
import javax.annotation.Nullable;
/** A lease service that manages the lease of remote blobs. */
public class LeaseService {
private final MemoizingEvaluator memoizingEvaluator;
@Nullable private final ActionCache actionCache;
public LeaseService(MemoizingEvaluator memoizingEvaluator, @Nullable ActionCache actionCache) {
this.memoizingEvaluator = memoizingEvaluator;
this.actionCache = actionCache;
}
/** Clean up internal state when files are evicted from remote CAS. */
public void handleMissingInputs(Set<ActionInput> missingActionInputs) {
if (missingActionInputs.isEmpty()) {
return;
}
// If any outputs are evicted, remove all remote metadata from skyframe and local action cache.
//
// With TTL based discarding and lease extension, remote cache eviction error won't happen if
// remote cache can guarantee the TTL. However, if it happens, it usually means the remote cache
// is under high load and it could possibly evict more blobs that Bazel wouldn't aware of.
// Following builds could still fail for the same error (caused by different blobs).
memoizingEvaluator.delete(
key -> {
if (key.functionName().equals(SkyFunctions.ACTION_EXECUTION)) {
try {
var value = memoizingEvaluator.getExistingValue(key);
return value instanceof ActionExecutionValue
&& isRemote((ActionExecutionValue) value);
} catch (InterruptedException ignored) {
return false;
}
}
return false;
});
if (actionCache != null) {
actionCache.removeIf(
entry -> !entry.getOutputFiles().isEmpty() || !entry.getOutputTrees().isEmpty());
}
}
private boolean isRemote(ActionExecutionValue value) {
return value.getAllFileValues().values().stream().anyMatch(FileArtifactValue::isRemote)
|| value.getAllTreeArtifactValues().values().stream().anyMatch(this::isRemoteTree);
}
private boolean isRemoteTree(TreeArtifactValue treeArtifactValue) {
return treeArtifactValue.getChildValues().values().stream()
.anyMatch(FileArtifactValue::isRemote)
|| treeArtifactValue
.getArchivedRepresentation()
.map(ar -> ar.archivedFileValue().isRemote())
.orElse(false);
}
}