blob: 30ae7911f3b6e3746d9fd44cab17162b0113c0b4 [file] [log] [blame]
leba40f2e722021-06-30 02:46:15 -07001// Copyright 2014 The Bazel Authors. All rights reserved.
Benjamin Petersonc868c472018-05-28 08:37:15 -07002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Googlerf9f22402024-01-19 07:28:52 -080014package com.google.devtools.build.lib.actions;
Benjamin Petersonc868c472018-05-28 08:37:15 -070015
Googler6fc91712023-03-10 07:47:29 -080016import static com.google.common.base.Preconditions.checkArgument;
17import static com.google.common.base.Preconditions.checkNotNull;
18
leba40f2e722021-06-30 02:46:15 -070019import com.google.common.base.MoreObjects;
Benjamin Petersonc868c472018-05-28 08:37:15 -070020import com.google.common.collect.ImmutableList;
Googler4b8334c2024-10-28 09:32:23 -070021import com.google.devtools.build.lib.actions.FileArtifactValue.ConstantMetadataValue;
Googlerf9f22402024-01-19 07:28:52 -080022import com.google.devtools.build.lib.skyframe.TreeArtifactValue;
Googler4b8334c2024-10-28 09:32:23 -070023import com.google.devtools.build.lib.util.Fingerprint;
Googler6fc91712023-03-10 07:47:29 -080024import com.google.devtools.build.lib.util.HashCodes;
leba40f2e722021-06-30 02:46:15 -070025import com.google.devtools.build.skyframe.SkyValue;
Benjamin Petersonc868c472018-05-28 08:37:15 -070026
27/** The artifacts behind a runfiles middleman. */
Googlerf9f22402024-01-19 07:28:52 -080028public final class RunfilesArtifactValue implements SkyValue {
Googler6fc91712023-03-10 07:47:29 -080029
Googlerf9f22402024-01-19 07:28:52 -080030 /** A callback for consuming artifacts in a runfiles tree. */
Googler6fc91712023-03-10 07:47:29 -080031 @FunctionalInterface
Googlerf9f22402024-01-19 07:28:52 -080032 public interface RunfilesConsumer<T> {
Googler6fc91712023-03-10 07:47:29 -080033 void accept(Artifact artifact, T metadata) throws InterruptedException;
34 }
35
leba40f2e722021-06-30 02:46:15 -070036 private final FileArtifactValue metadata;
Googler133c3ab2024-01-19 03:49:58 -080037 private final RunfilesTree runfilesTree;
leba40f2e722021-06-30 02:46:15 -070038
Googler6fc91712023-03-10 07:47:29 -080039 // Parallel lists.
40 private final ImmutableList<Artifact> files;
41 private final ImmutableList<FileArtifactValue> fileValues;
42
43 // Parallel lists.
44 private final ImmutableList<Artifact> trees;
45 private final ImmutableList<TreeArtifactValue> treeValues;
46
Googlerf9f22402024-01-19 07:28:52 -080047 public RunfilesArtifactValue(
Googler133c3ab2024-01-19 03:49:58 -080048 RunfilesTree runfilesTree,
Googler6fc91712023-03-10 07:47:29 -080049 ImmutableList<Artifact> files,
50 ImmutableList<FileArtifactValue> fileValues,
51 ImmutableList<Artifact> trees,
52 ImmutableList<TreeArtifactValue> treeValues) {
Googler133c3ab2024-01-19 03:49:58 -080053 this.runfilesTree = checkNotNull(runfilesTree);
Googler6fc91712023-03-10 07:47:29 -080054 this.files = checkNotNull(files);
55 this.fileValues = checkNotNull(fileValues);
56 this.trees = checkNotNull(trees);
57 this.treeValues = checkNotNull(treeValues);
58 checkArgument(
59 files.size() == fileValues.size() && trees.size() == treeValues.size(),
60 "Size mismatch: %s",
61 this);
Googler4b8334c2024-10-28 09:32:23 -070062
63 // Compute the digest of this runfiles tree by combining its layout and the digests of every
64 // artifact it references.
65 this.metadata = FileArtifactValue.createProxy(computeDigest());
66 }
67
68 private byte[] computeDigest() {
69 Fingerprint result = new Fingerprint();
70
71 result.addInt(runfilesTree.getMapping().size());
72 for (var entry : runfilesTree.getMapping().entrySet()) {
73 result.addPath(entry.getKey());
74 result.addBoolean(entry.getValue() != null);
75 if (entry.getValue() != null) {
76 result.addPath(entry.getValue().getExecPath());
77 }
78 }
79
80 result.addInt(files.size());
81 for (int i = 0; i < files.size(); i++) {
82 FileArtifactValue value =
83 files.get(i).isConstantMetadata() ? ConstantMetadataValue.INSTANCE : fileValues.get(i);
84 value.addTo(result);
85 }
86
87 result.addInt(trees.size());
88 for (int i = 0; i < trees.size(); i++) {
89 result.addBytes(treeValues.get(i).getDigest());
90 }
91
92 return result.digestAndReset();
leba40f2e722021-06-30 02:46:15 -070093 }
94
Googler651be712024-02-13 07:21:32 -080095 public RunfilesArtifactValue withOverriddenRunfilesTree(RunfilesTree overrideTree) {
Googler4b8334c2024-10-28 09:32:23 -070096 return new RunfilesArtifactValue(overrideTree, files, fileValues, trees, treeValues);
Googler651be712024-02-13 07:21:32 -080097 }
98
leba40f2e722021-06-30 02:46:15 -070099 /** Returns the data of the artifact for this value, as computed by the action cache checker. */
Googlerf9f22402024-01-19 07:28:52 -0800100 public FileArtifactValue getMetadata() {
leba40f2e722021-06-30 02:46:15 -0700101 return metadata;
102 }
103
Googler133c3ab2024-01-19 03:49:58 -0800104 /** Returns the runfiles tree this value represents. */
Googlerf9f22402024-01-19 07:28:52 -0800105 public RunfilesTree getRunfilesTree() {
Googler133c3ab2024-01-19 03:49:58 -0800106 return runfilesTree;
107 }
108
Googler6fc91712023-03-10 07:47:29 -0800109 /** Visits the file artifacts that this runfiles artifact expands to, together with their data. */
Googlerf9f22402024-01-19 07:28:52 -0800110 public void forEachFile(RunfilesConsumer<FileArtifactValue> consumer)
111 throws InterruptedException {
Googler6fc91712023-03-10 07:47:29 -0800112 for (int i = 0; i < files.size(); i++) {
113 consumer.accept(files.get(i), fileValues.get(i));
114 }
115 }
116
117 /** Visits the tree artifacts that this runfiles artifact expands to, together with their data. */
Googlerf9f22402024-01-19 07:28:52 -0800118 public void forEachTree(RunfilesConsumer<TreeArtifactValue> consumer)
119 throws InterruptedException {
Googler6fc91712023-03-10 07:47:29 -0800120 for (int i = 0; i < trees.size(); i++) {
121 consumer.accept(trees.get(i), treeValues.get(i));
122 }
123 }
124
leba40f2e722021-06-30 02:46:15 -0700125 @Override
126 public boolean equals(Object o) {
Googler133c3ab2024-01-19 03:49:58 -0800127 // This method, seemingly erroneously, does not check whether the runfilesTree of the two
128 // objects is equivalent. This is because it's costly (it involves flattening nested sets and
129 // even if one caches a fingerprint, it's still a fair amount of CPU) and because it's
130 // currently not necessary: RunfilesArtifactValue is only ever created as the SkyValue of
131 // runfiles middlemen and those are special-cased in ActionCacheChecker (see
132 // ActionCacheChecker.checkMiddlemanAction()): the checksum of a middleman artifact is the
133 // function of the checksum of all the artifacts on the inputs of the middleman action, which
134 // includes both the artifacts the runfiles tree links to and the runfiles input manifest,
135 // which in turn encodes the structure of the runfiles tree. The checksum of the middleman
136 // artifact is here as the "metadata" field, which *is* compared here, so the
137 // RunfilesArtifactValues of two runfiles middlemen will be equals iff they represent the same
138 // runfiles tree.
139 //
140 // Eventually, if we ever do away with runfiles input manifests, it will be necessary to change
141 // this (it's weird that one needs to do a round-trip to the file system to determine the
142 // checksum of a runfiles tree), but that's not happening anytime soon.
leba40f2e722021-06-30 02:46:15 -0700143 if (this == o) {
144 return true;
145 }
Googler6f48f1c2024-04-16 14:29:09 -0700146 if (!(o instanceof RunfilesArtifactValue that)) {
leba40f2e722021-06-30 02:46:15 -0700147 return false;
148 }
leba40f2e722021-06-30 02:46:15 -0700149 return metadata.equals(that.metadata)
Googler6fc91712023-03-10 07:47:29 -0800150 && files.equals(that.files)
151 && fileValues.equals(that.fileValues)
152 && trees.equals(that.trees)
153 && treeValues.equals(that.treeValues);
leba40f2e722021-06-30 02:46:15 -0700154 }
155
156 @Override
157 public int hashCode() {
Googler6fc91712023-03-10 07:47:29 -0800158 return HashCodes.hashObjects(metadata, files, fileValues, trees, treeValues);
leba40f2e722021-06-30 02:46:15 -0700159 }
160
161 @Override
162 public String toString() {
163 return MoreObjects.toStringHelper(this)
Googler6fc91712023-03-10 07:47:29 -0800164 .add("metadata", metadata)
165 .add("files", files)
166 .add("fileValues", fileValues)
167 .add("trees", trees)
168 .add("treeValues", treeValues)
leba40f2e722021-06-30 02:46:15 -0700169 .toString();
Benjamin Petersonc868c472018-05-28 08:37:15 -0700170 }
Benjamin Petersonc868c472018-05-28 08:37:15 -0700171}