blob: 40a0804c22174c37e260a6058ee756f954c8c102 [file] [log] [blame]
// 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.actions;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.Artifact.ArchivedTreeArtifact;
import com.google.devtools.build.lib.actions.Artifact.ArtifactSerializationContext;
import com.google.devtools.build.lib.actions.Artifact.DerivedArtifact;
import com.google.devtools.build.lib.actions.Artifact.SourceArtifact;
import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
import com.google.devtools.build.lib.skyframe.serialization.AsyncDeserializationContext;
import com.google.devtools.build.lib.skyframe.serialization.AsyncDeserializationContext.FieldSetter;
import com.google.devtools.build.lib.skyframe.serialization.DeferredObjectCodec;
import com.google.devtools.build.lib.skyframe.serialization.DeferredObjectCodec.DeferredValue;
import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
import com.google.devtools.build.lib.skyframe.serialization.SerializationContext;
import com.google.devtools.build.lib.skyframe.serialization.SerializationException;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.errorprone.annotations.Keep;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import java.io.IOException;
/**
* Codec implementations for {@link Artifact} subclasses.
*
* <p>Each Artifact's codec implementation is split into two codecs: the main codec that handles the
* individual fields, and a value-sharing codec.
*/
public final class ArtifactCodecs {
// TODO: b/359437873 - generate with @AutoCodec.
public static final ImmutableList<ObjectCodec<? extends Artifact>> VALUE_SHARING_CODECS =
ImmutableList.of(
new DerivedArtifactValueSharingCodec(),
new SourceArtifactValueSharingCodec(),
new SpecialArtifactValueSharingCodec());
@Keep
private static final class DerivedArtifactValueSharingCodec
extends DeferredObjectCodec<DerivedArtifact> {
@Override
public boolean autoRegister() {
return false;
}
@Override
public Class<DerivedArtifact> getEncodedClass() {
return DerivedArtifact.class;
}
@Override
public void serialize(
SerializationContext context, DerivedArtifact obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
context.putSharedValue(
obj, /* distinguisher= */ null, DerivedArtifactCodec.INSTANCE, codedOut);
}
@Override
public DeferredValue<DerivedArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
SimpleDeferredValue<DerivedArtifact> value = SimpleDeferredValue.create();
context.getSharedValue(
codedIn,
/* distinguisher= */ null,
DerivedArtifactCodec.INSTANCE,
value,
SimpleDeferredValue::set);
return value;
}
}
/**
* {@link ObjectCodec} for {@link DerivedArtifact}.
*
* <p>To be kept in sync with {@link SpecialArtifactCodec}.
*/
@Keep // Used by reflection.
private static final class DerivedArtifactCodec extends DeferredObjectCodec<DerivedArtifact> {
private static final DerivedArtifactCodec INSTANCE = new DerivedArtifactCodec();
@Override
public Class<DerivedArtifact> getEncodedClass() {
return DerivedArtifact.class;
}
@Override
public void serialize(
SerializationContext context, DerivedArtifact obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
context.serialize(obj.getRoot(), codedOut);
context.serialize(obj.getRootRelativePath(), codedOut);
serializeOrOmitGeneratingActionKey(context, obj, codedOut);
}
@Override
public DeferredValue<DerivedArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
DeserializedDerivedArtifactBuilder builder = new DeserializedDerivedArtifactBuilder(context);
context.deserialize(codedIn, builder, DeserializedDerivedArtifactBuilder::setRoot);
context.deserialize(
codedIn, builder, DeserializedDerivedArtifactBuilder::setRootRelativePath);
deserializeOrGetGeneratingActionKey(
context, codedIn, builder, DeserializedDerivedArtifactBuilder::setGeneratingActionKey);
return builder;
}
}
private static class DeserializedDerivedArtifactBuilder
implements DeferredValue<DerivedArtifact> {
private final AsyncDeserializationContext context;
private ArtifactRoot root;
private PathFragment rootRelativePath;
private ActionLookupData generatingActionKey;
private DeserializedDerivedArtifactBuilder(AsyncDeserializationContext context) {
this.context = context;
}
@Override
public DerivedArtifact call() {
return context
.getDependency(ArtifactSerializationContext.class)
.intern(
new DerivedArtifact(
root,
getExecPathForDeserialization(root, rootRelativePath, generatingActionKey),
generatingActionKey),
context);
}
private static void setRoot(DeserializedDerivedArtifactBuilder builder, Object value) {
builder.root = (ArtifactRoot) value;
}
private static void setRootRelativePath(
DeserializedDerivedArtifactBuilder builder, Object value) {
builder.rootRelativePath = (PathFragment) value;
}
private static void setGeneratingActionKey(
DeserializedDerivedArtifactBuilder builder, Object value) {
builder.generatingActionKey = (ActionLookupData) value;
}
}
private static void serializeOrOmitGeneratingActionKey(
SerializationContext context, DerivedArtifact obj, CodedOutputStream codedOut)
throws IOException, SerializationException {
boolean include =
context
.getDependency(ArtifactSerializationContext.class)
.includeGeneratingActionKey(obj, context);
codedOut.writeBoolNoTag(include);
if (include) {
context.serialize(obj.getGeneratingActionKey(), codedOut);
}
}
private static <T> void deserializeOrGetGeneratingActionKey(
AsyncDeserializationContext context,
CodedInputStream codedIn,
T builder,
FieldSetter<T> setter)
throws IOException, SerializationException {
boolean included = codedIn.readBool();
if (included) {
context.deserialize(codedIn, builder, setter);
} else {
ActionLookupData generatingActionKey =
context
.getDependency(ArtifactSerializationContext.class)
.getOmittedGeneratingActionKey(context);
setter.set(builder, generatingActionKey);
}
}
private static PathFragment getExecPathForDeserialization(
ArtifactRoot root, PathFragment rootRelativePath, Object generatingActionKey) {
Preconditions.checkArgument(
!root.isSourceRoot(),
"Root not derived: %s (rootRelativePath=%s, generatingActionKey=%s)",
root,
rootRelativePath,
generatingActionKey);
Preconditions.checkArgument(
root.getRoot().isAbsolute() == rootRelativePath.isAbsolute(),
"Illegal root relative path: %s (root=%s, generatingActionKey=%s)",
rootRelativePath,
root,
generatingActionKey);
return root.getExecPath().getRelative(rootRelativePath);
}
@Keep
private static final class SourceArtifactValueSharingCodec
extends DeferredObjectCodec<SourceArtifact> {
@Override
public boolean autoRegister() {
return false;
}
@Override
public Class<SourceArtifact> getEncodedClass() {
return SourceArtifact.class;
}
@Override
public void serialize(
SerializationContext context, SourceArtifact obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
context.putSharedValue(
obj, /* distinguisher= */ null, SourceArtifactCodec.INSTANCE, codedOut);
}
@Override
public DeferredValue<SourceArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
SimpleDeferredValue<SourceArtifact> value = SimpleDeferredValue.create();
context.getSharedValue(
codedIn,
/* distinguisher= */ null,
SourceArtifactCodec.INSTANCE,
value,
SimpleDeferredValue::set);
return value;
}
}
/** {@link ObjectCodec} for {@link SourceArtifact} */
@Keep // Used by reflection.
private static final class SourceArtifactCodec extends DeferredObjectCodec<SourceArtifact> {
private static final SourceArtifactCodec INSTANCE = new SourceArtifactCodec();
@Override
public Class<SourceArtifact> getEncodedClass() {
return SourceArtifact.class;
}
@Override
public void serialize(
SerializationContext context, SourceArtifact obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
context.serialize(obj.getExecPath(), codedOut);
context.serialize(obj.getRoot(), codedOut);
context.serialize(obj.getArtifactOwner(), codedOut);
}
@Override
public DeferredValue<SourceArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
DeserializedSourceArtifactBuilder builder =
new DeserializedSourceArtifactBuilder(
context.getDependency(ArtifactSerializationContext.class));
context.deserialize(codedIn, builder, DeserializedSourceArtifactBuilder::setExecPath);
context.deserialize(codedIn, builder, DeserializedSourceArtifactBuilder::setRoot);
context.deserialize(codedIn, builder, DeserializedSourceArtifactBuilder::setOwner);
return builder;
}
}
private static class DeserializedSourceArtifactBuilder implements DeferredValue<SourceArtifact> {
private final ArtifactSerializationContext context;
private PathFragment execPath;
private ArtifactRoot root;
private ArtifactOwner owner;
private DeserializedSourceArtifactBuilder(ArtifactSerializationContext context) {
this.context = context;
}
@Override
public SourceArtifact call() {
return context.getSourceArtifact(execPath, root, owner);
}
private static void setExecPath(DeserializedSourceArtifactBuilder builder, Object value) {
builder.execPath = (PathFragment) value;
}
private static void setRoot(DeserializedSourceArtifactBuilder builder, Object value) {
builder.root = (ArtifactRoot) value;
}
private static void setOwner(DeserializedSourceArtifactBuilder builder, Object value) {
builder.owner = (ArtifactOwner) value;
}
}
@Keep
private static final class SpecialArtifactValueSharingCodec
extends DeferredObjectCodec<SpecialArtifact> {
@Override
public boolean autoRegister() {
return false;
}
@Override
public Class<SpecialArtifact> getEncodedClass() {
return SpecialArtifact.class;
}
@Override
public void serialize(
SerializationContext context, SpecialArtifact obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
context.putSharedValue(
obj, /* distinguisher= */ null, SpecialArtifactCodec.INSTANCE, codedOut);
}
@Override
public DeferredValue<SpecialArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
SimpleDeferredValue<SpecialArtifact> value = SimpleDeferredValue.create();
context.getSharedValue(
codedIn,
/* distinguisher= */ null,
SpecialArtifactCodec.INSTANCE,
value,
SimpleDeferredValue::set);
return value;
}
}
/**
* {@link ObjectCodec} for {@link SpecialArtifact}.
*
* <p>To be kept in sync with {@link DerivedArtifactCodec}.
*/
@Keep // Used by reflection.
private static final class SpecialArtifactCodec extends DeferredObjectCodec<SpecialArtifact> {
private static final SpecialArtifactCodec INSTANCE = new SpecialArtifactCodec();
@Override
public Class<SpecialArtifact> getEncodedClass() {
return SpecialArtifact.class;
}
@Override
public void serialize(
SerializationContext context, SpecialArtifact obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
context.serialize(obj.getRoot(), codedOut);
context.serialize(obj.getRootRelativePath(), codedOut);
serializeOrOmitGeneratingActionKey(context, obj, codedOut);
context.serialize(obj.getSpecialArtifactType(), codedOut);
}
@Override
public DeferredValue<SpecialArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
DeserializedSpecialArtifactBuilder builder = new DeserializedSpecialArtifactBuilder(context);
context.deserialize(codedIn, builder, DeserializedSpecialArtifactBuilder::setRoot);
context.deserialize(
codedIn, builder, DeserializedSpecialArtifactBuilder::setRootRelativePath);
deserializeOrGetGeneratingActionKey(
context, codedIn, builder, DeserializedSpecialArtifactBuilder::setGeneratingActionKey);
context.deserialize(codedIn, builder, DeserializedSpecialArtifactBuilder::setType);
return builder;
}
}
private static final class DeserializedSpecialArtifactBuilder
implements DeferredValue<SpecialArtifact> {
private final AsyncDeserializationContext context;
private ArtifactRoot root;
private PathFragment rootRelativePath;
private ActionLookupData generatingActionKey;
private SpecialArtifactType type;
private DeserializedSpecialArtifactBuilder(AsyncDeserializationContext context) {
this.context = context;
}
@Override
public SpecialArtifact call() {
return (SpecialArtifact)
context
.getDependency(ArtifactSerializationContext.class)
.intern(
new SpecialArtifact(
root,
getExecPathForDeserialization(root, rootRelativePath, generatingActionKey),
generatingActionKey,
type),
context);
}
private static void setRoot(DeserializedSpecialArtifactBuilder builder, Object value) {
builder.root = (ArtifactRoot) value;
}
private static void setRootRelativePath(
DeserializedSpecialArtifactBuilder builder, Object value) {
builder.rootRelativePath = (PathFragment) value;
}
private static void setGeneratingActionKey(
DeserializedSpecialArtifactBuilder builder, Object value) {
builder.generatingActionKey = (ActionLookupData) value;
}
private static void setType(DeserializedSpecialArtifactBuilder builder, Object value) {
builder.type = (SpecialArtifactType) value;
}
}
@SuppressWarnings("unused") // Codec used by reflection.
private static final class ArchivedTreeArtifactCodec
extends DeferredObjectCodec<ArchivedTreeArtifact> {
@Override
public Class<ArchivedTreeArtifact> getEncodedClass() {
return ArchivedTreeArtifact.class;
}
@Override
public void serialize(
SerializationContext context, ArchivedTreeArtifact obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
PathFragment derivedTreeRoot = obj.getRoot().getExecPath().subFragment(1, 2);
context.serialize(obj.getParent(), codedOut);
context.serialize(derivedTreeRoot, codedOut);
context.serialize(obj.getRootRelativePath(), codedOut);
}
@Override
public DeferredValue<ArchivedTreeArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
DeserializedArchivedTreeArtifactBuilder builder =
new DeserializedArchivedTreeArtifactBuilder();
context.deserialize(
codedIn, builder, DeserializedArchivedTreeArtifactBuilder::setTreeArtifact);
context.deserialize(
codedIn, builder, DeserializedArchivedTreeArtifactBuilder::setDerivedTreeRoot);
context.deserialize(
codedIn, builder, DeserializedArchivedTreeArtifactBuilder::setRootRelativePath);
return builder;
}
}
private static class DeserializedArchivedTreeArtifactBuilder
implements DeferredValue<ArchivedTreeArtifact> {
private SpecialArtifact treeArtifact;
private PathFragment derivedTreeRoot;
private PathFragment rootRelativePath;
@Override
public ArchivedTreeArtifact call() {
return ArchivedTreeArtifact.createWithCustomDerivedTreeRoot(
treeArtifact, derivedTreeRoot, rootRelativePath);
}
private static void setTreeArtifact(
DeserializedArchivedTreeArtifactBuilder builder, Object value) {
builder.treeArtifact = (SpecialArtifact) value;
}
private static void setDerivedTreeRoot(
DeserializedArchivedTreeArtifactBuilder builder, Object value) {
builder.derivedTreeRoot = (PathFragment) value;
}
private static void setRootRelativePath(
DeserializedArchivedTreeArtifactBuilder builder, Object value) {
builder.rootRelativePath = (PathFragment) value;
}
}
@SuppressWarnings("unused") // Used by reflection.
private static final class TreeFileArtifactCodec extends DeferredObjectCodec<TreeFileArtifact> {
@Override
public Class<TreeFileArtifact> getEncodedClass() {
return TreeFileArtifact.class;
}
@Override
public void serialize(
SerializationContext context, TreeFileArtifact obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
context.serialize(obj.getParent(), codedOut);
context.serialize(obj.getParentRelativePath(), codedOut);
serializeOrOmitGeneratingActionKey(context, obj, codedOut);
}
@Override
public DeferredValue<TreeFileArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
DeserializedTreeFileArtifactBuilder builder = new DeserializedTreeFileArtifactBuilder();
context.deserialize(codedIn, builder, DeserializedTreeFileArtifactBuilder::setParent);
context.deserialize(
codedIn, builder, DeserializedTreeFileArtifactBuilder::setParentRelativePath);
deserializeOrGetGeneratingActionKey(
context, codedIn, builder, DeserializedTreeFileArtifactBuilder::setGeneratingActionKey);
return builder;
}
}
private static class DeserializedTreeFileArtifactBuilder
implements DeferredValue<TreeFileArtifact> {
private SpecialArtifact parent;
private PathFragment parentRelativePath;
private ActionLookupData generatingActionKey;
@Override
public TreeFileArtifact call() {
return new TreeFileArtifact(parent, parentRelativePath, generatingActionKey);
}
private static void setParent(DeserializedTreeFileArtifactBuilder builder, Object value) {
builder.parent = (SpecialArtifact) value;
}
private static void setParentRelativePath(
DeserializedTreeFileArtifactBuilder builder, Object value) {
builder.parentRelativePath = (PathFragment) value;
}
private static void setGeneratingActionKey(
DeserializedTreeFileArtifactBuilder builder, Object value) {
builder.generatingActionKey = (ActionLookupData) value;
}
}
private ArtifactCodecs() {}
}