blob: ecfbaca8e87e5ce00f0307996041203b784b83e8 [file]
// Copyright 2024 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.skyframe;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.devtools.build.lib.actions.ActionLookupData;
import com.google.devtools.build.lib.actions.ActionLookupKey;
import com.google.devtools.build.lib.actions.ActionLookupSummaryKey;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.skyframe.serialization.DependOnFutureShim.DefaultDependOnFutureShim;
import com.google.devtools.build.lib.skyframe.serialization.DeserializedSkyValue;
import com.google.devtools.build.lib.skyframe.serialization.SerializationException;
import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever;
import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.NoCachedData;
import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.Restart;
import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.RetrievalContext;
import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.RetrievalResult;
import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.RetrievedValue;
import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.SerializableSkyKeyComputeState;
import com.google.devtools.build.lib.skyframe.serialization.analysis.RemoteAnalysisCacheClient;
import com.google.devtools.build.lib.skyframe.serialization.analysis.RemoteAnalysisCacheReaderDepsProvider;
import com.google.devtools.build.lib.skyframe.serialization.analysis.SkycacheUploadClient;
import com.google.devtools.build.lib.skyframe.serialization.analysis.proto.MissReason;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.util.function.Supplier;
/**
* A wrapper around {@link SkyValueRetriever} to handle Bazel-on-Skyframe specific logic, metrics
* gathering, and error handling.
*/
public final class SkyValueRetrieverUtils {
public static RetrievalResult retrieveRemoteSkyValue(
SkyKey key,
Environment env,
RemoteAnalysisCacheReaderDepsProvider analysisCachingDeps,
Supplier<? extends SerializableSkyKeyComputeState> stateSupplier)
throws InterruptedException {
if (env.inErrorBubbling()) {
// Remote retrieval during error bubbling causes incorrect error propagation. See b/449016469.
return new NoCachedData(MissReason.MISS_REASON_NOT_ATTEMPTED);
}
if (analysisCachingDeps.shouldBailOutOnMissingFingerprint()) {
return new NoCachedData(MissReason.MISS_REASON_NOT_ATTEMPTED);
}
Label label =
switch (key) {
case ActionLookupKey alk -> alk.getLabel();
case ActionLookupData ald -> ald.getLabel();
case ActionLookupSummaryKey summaryKey -> summaryKey.argument().getLabel();
case Artifact artifact -> artifact.getOwnerLabel();
default -> throw new IllegalStateException("unexpected key: " + key.getCanonicalName());
};
if (label == null) {
// If there's no label, there's no cached data.
return new NoCachedData(MissReason.MISS_REASON_NOT_ATTEMPTED);
}
SkyValueRetriever retriever = analysisCachingDeps.getSkyValueRetriever();
RemoteAnalysisCacheClient client = analysisCachingDeps.getAnalysisCacheClient();
if (retriever == null || client == null) {
return new NoCachedData(MissReason.MISS_REASON_NOT_ATTEMPTED);
}
RetrievalResult retrievalResult = null;
RetrievalContext state = env.getState(stateSupplier).getRetrievalContext();
try {
retrievalResult =
retriever.tryRetrieve(env, new DefaultDependOnFutureShim(env), client, key, state);
analysisCachingDeps.recordRetrievalResult(retrievalResult, key);
} catch (SerializationException e) {
// Don't crash the build if deserialization failed. Gracefully fallback to local evaluation.
analysisCachingDeps.recordSerializationException(e, key);
retrievalResult = new NoCachedData(e.getReason());
} catch (RuntimeException | InterruptedException e) {
throw e;
} finally {
if (retrievalResult == Restart.RESTART) {
state.addRestart();
}
}
if (retrievalResult instanceof RetrievedValue(SkyValue v)
&& !(v instanceof DeserializedSkyValue)) {
throw new IllegalStateException(
"deserialized SkyValue of type "
+ v.getClass().getCanonicalName()
+ " does not implement DeserializedSkyValue. Try using"
+ " @AutoCodec(deserializedInterface = DeserializedSkyValue.class)");
}
return retrievalResult;
}
public static void tryUploadAsync(
RemoteAnalysisCacheReaderDepsProvider cachingDeps,
SkyKey key,
SkyValue value,
Environment env)
throws InterruptedException {
if (!cachingDeps.mode().isAsyncUpload()) {
return;
}
SkycacheUploadClient uploadClient = cachingDeps.getSkycacheUploadClient();
// TODO(b/527929697): Handle null uploadClient properly (e.g. fail the build cleanly).
checkNotNull(uploadClient).tryUpload(key, value, env);
}
private SkyValueRetrieverUtils() {}
}