blob: 76394ac0e5c6ecf36445c5e8d5c4be45a40472bd [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 static com.google.devtools.build.lib.actions.Artifact.OMITTED_FOR_SERIALIZATION;
import com.google.common.base.Preconditions;
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.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.devtools.build.lib.vfs.Root;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import java.io.IOException;
/** Codec implementations for {@link Artifact} subclasses. */
final class ArtifactCodecs {
@SuppressWarnings("unused") // Codec used by reflection.
private static final class DerivedArtifactCodec extends DeferredObjectCodec<DerivedArtifact> {
@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);
context.serialize(getGeneratingActionKeyForSerialization(obj, context), codedOut);
}
@Override
public DeferredValue<DerivedArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
DeserializedDerivedArtifactBuilder builder =
new DeserializedDerivedArtifactBuilder(
context.getDependency(ArtifactSerializationContext.class));
context.deserialize(codedIn, builder, DeserializedDerivedArtifactBuilder::setRoot);
context.deserialize(
codedIn, builder, DeserializedDerivedArtifactBuilder::setRootRelativePath);
context.deserialize(
codedIn, builder, DeserializedDerivedArtifactBuilder::setGeneratingActionKey);
return builder;
}
}
private static class DeserializedDerivedArtifactBuilder
implements DeferredValue<DerivedArtifact> {
private final ArtifactSerializationContext context;
private ArtifactRoot root;
private PathFragment rootRelativePath;
private Object generatingActionKey;
private DeserializedDerivedArtifactBuilder(ArtifactSerializationContext context) {
this.context = context;
}
@Override
public DerivedArtifact call() {
return context.intern(
new DerivedArtifact(
root,
getExecPathForDeserialization(root, rootRelativePath, generatingActionKey),
generatingActionKey));
}
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 = value;
}
}
private static Object getGeneratingActionKeyForSerialization(
DerivedArtifact artifact, SerializationContext context) {
return context
.getDependency(ArtifactSerializationContext.class)
.includeGeneratingActionKey(artifact)
? artifact.getGeneratingActionKey()
: OMITTED_FOR_SERIALIZATION;
}
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);
}
/** {@link ObjectCodec} for {@link SourceArtifact} */
@SuppressWarnings("unused") // Used by reflection.
private static final class SourceArtifactCodec extends DeferredObjectCodec<SourceArtifact> {
@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().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 Root 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 = (Root) value;
}
private static void setOwner(DeserializedSourceArtifactBuilder builder, Object value) {
builder.owner = (ArtifactOwner) value;
}
}
// Keep in sync with DerivedArtifactCodec.
@SuppressWarnings("unused") // Used by reflection.
private static final class SpecialArtifactCodec extends DeferredObjectCodec<SpecialArtifact> {
@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);
context.serialize(getGeneratingActionKeyForSerialization(obj, context), codedOut);
context.serialize(obj.getSpecialArtifactType(), codedOut);
}
@Override
public DeferredValue<SpecialArtifact> deserializeDeferred(
AsyncDeserializationContext context, CodedInputStream codedIn)
throws SerializationException, IOException {
DeserializedSpecialArtifactBuilder builder =
new DeserializedSpecialArtifactBuilder(
context.getDependency(ArtifactSerializationContext.class));
context.deserialize(codedIn, builder, DeserializedSpecialArtifactBuilder::setRoot);
context.deserialize(
codedIn, builder, DeserializedSpecialArtifactBuilder::setRootRelativePath);
context.deserialize(
codedIn, builder, DeserializedSpecialArtifactBuilder::setGeneratingActionKey);
context.deserialize(codedIn, builder, DeserializedSpecialArtifactBuilder::setType);
return builder;
}
}
private static class DeserializedSpecialArtifactBuilder
implements DeferredValue<SpecialArtifact> {
private final ArtifactSerializationContext context;
private ArtifactRoot root;
private PathFragment rootRelativePath;
private Object generatingActionKey;
private SpecialArtifactType type;
private DeserializedSpecialArtifactBuilder(ArtifactSerializationContext context) {
this.context = context;
}
@Override
public SpecialArtifact call() {
return (SpecialArtifact)
context.intern(
new SpecialArtifact(
root,
getExecPathForDeserialization(root, rootRelativePath, generatingActionKey),
generatingActionKey,
type));
}
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 = 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() {
Object generatingActionKey =
treeArtifact.hasGeneratingActionKey()
? treeArtifact.getGeneratingActionKey()
: OMITTED_FOR_SERIALIZATION;
return ArchivedTreeArtifact.createInternal(
treeArtifact, derivedTreeRoot, rootRelativePath, generatingActionKey);
}
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);
context.serialize(getGeneratingActionKeyForSerialization(obj, context), 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);
context.deserialize(
codedIn, builder, DeserializedTreeFileArtifactBuilder::setGeneratingActionKey);
return builder;
}
}
private static class DeserializedTreeFileArtifactBuilder
implements DeferredValue<TreeFileArtifact> {
private SpecialArtifact parent;
private PathFragment parentRelativePath;
private Object 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 = value;
}
}
private ArtifactCodecs() {}
}