| // Copyright 2014 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 com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Sets; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; |
| import com.google.devtools.build.lib.actions.FileArtifactValue; |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| import javax.annotation.Nullable; |
| |
| /** |
| * Storage layer for data associated with outputs of an action. |
| * |
| * <p>Data is mainly stored in three maps, {@link #artifactData}, {@link #treeArtifactData} and |
| * {@link #treeArtifactContents}, all of which are keyed on an {@link Artifact}. For each of these |
| * maps, this class exposes standard methods such as {@code get}, {@code put}, {@code add}, and |
| * {@code getAll}. |
| * |
| * <p>This implementation aggressively stores all data. Subclasses may override mutating methods to |
| * avoid storing unnecessary data. |
| */ |
| @ThreadSafe |
| class OutputStore { |
| |
| private final ConcurrentMap<Artifact, FileArtifactValue> artifactData = new ConcurrentHashMap<>(); |
| |
| private final ConcurrentMap<Artifact, TreeArtifactValue> treeArtifactData = |
| new ConcurrentHashMap<>(); |
| |
| private final ConcurrentMap<Artifact, Set<TreeFileArtifact>> treeArtifactContents = |
| new ConcurrentHashMap<>(); |
| |
| private final Set<Artifact> injectedFiles = Sets.newConcurrentHashSet(); |
| |
| @Nullable |
| final FileArtifactValue getArtifactData(Artifact artifact) { |
| return artifactData.get(artifact); |
| } |
| |
| void putArtifactData(Artifact artifact, FileArtifactValue value) { |
| artifactData.put(artifact, value); |
| } |
| |
| final ImmutableMap<Artifact, FileArtifactValue> getAllArtifactData() { |
| return ImmutableMap.copyOf(artifactData); |
| } |
| |
| @Nullable |
| final TreeArtifactValue getTreeArtifactData(Artifact artifact) { |
| return treeArtifactData.get(artifact); |
| } |
| |
| void putTreeArtifactData(Artifact artifact, TreeArtifactValue value) { |
| treeArtifactData.put(artifact, value); |
| } |
| |
| /** |
| * Returns data for TreeArtifacts that was computed during execution. May contain copies of {@link |
| * TreeArtifactValue#MISSING_TREE_ARTIFACT}. |
| */ |
| final ImmutableMap<Artifact, TreeArtifactValue> getAllTreeArtifactData() { |
| return ImmutableMap.copyOf(treeArtifactData); |
| } |
| |
| /** |
| * Returns a set of the given tree artifact's contents. |
| * |
| * <p>If the return value is {@code null}, this means nothing was injected, and the output |
| * TreeArtifact is to have its values read from disk instead. |
| */ |
| @Nullable |
| final Set<TreeFileArtifact> getTreeArtifactContents(Artifact artifact) { |
| return treeArtifactContents.get(artifact); |
| } |
| |
| void addTreeArtifactContents(Artifact artifact, TreeFileArtifact contents) { |
| Preconditions.checkArgument(artifact.isTreeArtifact(), artifact); |
| treeArtifactContents.computeIfAbsent(artifact, a -> Sets.newConcurrentHashSet()).add(contents); |
| } |
| |
| void injectRemoteFile(Artifact output, byte[] digest, long size, int locationIndex) { |
| injectOutputData( |
| output, new FileArtifactValue.RemoteFileArtifactValue(digest, size, locationIndex)); |
| } |
| |
| final void injectOutputData(Artifact output, FileArtifactValue artifactValue) { |
| injectedFiles.add(output); |
| artifactData.put(output, artifactValue); |
| } |
| |
| /** Returns a set that tracks which Artifacts have had metadata injected. */ |
| final Set<Artifact> injectedFiles() { |
| return injectedFiles; |
| } |
| |
| /** Clears all data in this store. */ |
| final void clear() { |
| artifactData.clear(); |
| treeArtifactData.clear(); |
| treeArtifactContents.clear(); |
| injectedFiles.clear(); |
| } |
| |
| /** Clears data about a specific Artifact from this store. */ |
| final void remove(Artifact artifact) { |
| artifactData.remove(artifact); |
| treeArtifactData.remove(artifact); |
| treeArtifactContents.remove(artifact); |
| injectedFiles.remove(artifact); |
| } |
| } |