Refactoring: makes the code simpler by deleting Metadata and InputArtifactData.

(minor) ActionFS now implements MetadataProvider.getInput

PiperOrigin-RevId: 199575194
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 27f1e62..fbfcff8 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -808,6 +808,7 @@
         "//src/main/java/com/google/devtools/build/lib:runtime",
         "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
         "//src/main/java/com/google/devtools/build/lib:util",
+        "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/cache",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/downloader",
         "//src/main/java/com/google/devtools/build/lib/buildeventstream",
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java b/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
index 63256d7..4b72809 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
@@ -22,12 +22,12 @@
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata.MiddlemanType;
 import com.google.devtools.build.lib.actions.cache.ActionCache;
 import com.google.devtools.build.lib.actions.cache.DigestUtils;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.MetadataHandler;
 import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics.MissReason;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -51,27 +51,7 @@
  */
 public class ActionCacheChecker {
   private static final byte[] EMPTY_DIGEST = new byte[0];
-  private static final Metadata CONSTANT_METADATA = new Metadata() {
-    @Override
-    public FileStateType getType() {
-      return FileStateType.REGULAR_FILE;
-    }
-
-    @Override
-    public byte[] getDigest() {
-      return EMPTY_DIGEST;
-    }
-
-    @Override
-    public long getSize() {
-      return 0;
-    }
-
-    @Override
-    public long getModifiedTime() {
-      return -1;
-    }
-  };
+  private static final FileArtifactValue CONSTANT_METADATA = new ConstantMetadataValue();
 
   private final ActionCache actionCache;
   private final ActionKeyContext actionKeyContext;
@@ -164,7 +144,7 @@
     Iterable<Artifact> artifacts = checkOutput
         ? Iterables.concat(action.getOutputs(), actionInputs)
         : actionInputs;
-    Map<String, Metadata> mdMap = new HashMap<>();
+    Map<String, FileArtifactValue> mdMap = new HashMap<>();
     for (Artifact artifact : artifacts) {
       mdMap.put(artifact.getExecPathString(), getMetadataMaybe(metadataHandler, artifact));
     }
@@ -324,8 +304,8 @@
     return false;
   }
 
-  private static Metadata getMetadataOrConstant(MetadataHandler metadataHandler, Artifact artifact)
-      throws IOException {
+  private static FileArtifactValue getMetadataOrConstant(
+      MetadataHandler metadataHandler, Artifact artifact) throws IOException {
     if (artifact.isConstantMetadata()) {
       return CONSTANT_METADATA;
     } else {
@@ -337,7 +317,8 @@
   // to trigger a re-execution, so we should catch the IOException explicitly there. In others, we
   // should propagate the exception, because it is unexpected (e.g., bad file system state).
   @Nullable
-  private static Metadata getMetadataMaybe(MetadataHandler metadataHandler, Artifact artifact) {
+  private static FileArtifactValue getMetadataMaybe(
+      MetadataHandler metadataHandler, Artifact artifact) {
     try {
       return getMetadataOrConstant(metadataHandler, artifact);
     } catch (IOException e) {
@@ -373,7 +354,7 @@
         // 'constant' metadata for the volatile workspace status output. The volatile output
         // contains information such as timestamps, and even when --stamp is enabled, we don't want
         // to rebuild everything if only that file changes.
-        Metadata metadata = getMetadataOrConstant(metadataHandler, output);
+        FileArtifactValue metadata = getMetadataOrConstant(metadataHandler, output);
         Preconditions.checkState(metadata != null);
         entry.addFile(output.getExecPath(), metadata);
       }
@@ -554,4 +535,33 @@
       this.cacheKey = Preconditions.checkNotNull(cacheKey);
     }
   }
+
+  private static final class ConstantMetadataValue extends FileArtifactValue
+      implements FileArtifactValue.Singleton {
+    @Override
+    public FileStateType getType() {
+      return FileStateType.REGULAR_FILE;
+    }
+
+    @Override
+    public byte[] getDigest() {
+      return EMPTY_DIGEST;
+    }
+
+    @Override
+    public long getSize() {
+      return 0;
+    }
+
+    @Override
+    public long getModifiedTime() {
+      return -1;
+    }
+
+    @Override
+    public boolean wasModifiedSinceDigest(Path path) {
+      throw new UnsupportedOperationException(
+          "ConstantMetadataValue doesn't support wasModifiedSinceDigest " + path.toString());
+    }
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionInputMap.java b/src/main/java/com/google/devtools/build/lib/actions/ActionInputMap.java
index c938b07..09014fe 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionInputMap.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionInputMap.java
@@ -14,15 +14,14 @@
 package com.google.devtools.build.lib.actions;
 
 import com.google.common.base.Preconditions;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import java.util.Arrays;
 import javax.annotation.Nullable;
 
 /**
  * Helper for {@link MetadataProvider} implementations.
  *
- * <p>Allows {@link Metadata} lookups by exec path or {@link ActionInput}. <i>Also</i> allows {@link
- * ActionInput} to be looked up by exec path.
+ * <p>Allows {@link FileArtifactValue} lookups by exec path or {@link ActionInput}. <i>Also</i>
+ * allows {@link ActionInput} to be looked up by exec path.
  *
  * <p>This class is thread-compatible.
  */
@@ -30,7 +29,7 @@
   /**
    * {@link ActionInput} keys stored in even indices
    *
-   * <p>{@link Metadata} values stored in odd indices
+   * <p>{@link FileArtifactValue} values stored in odd indices
    */
   private Object[] data;
 
@@ -55,19 +54,19 @@
 
   @Nullable
   @Override
-  public Metadata getMetadata(ActionInput input) {
+  public FileArtifactValue getMetadata(ActionInput input) {
     return getMetadata(input.getExecPathString());
   }
 
   @Nullable
-  public Metadata getMetadata(String execPathString) {
+  public FileArtifactValue getMetadata(String execPathString) {
     int hashCode = execPathString.hashCode();
     int probe = getProbe(hashCode);
     ActionInput nextKey;
     while ((nextKey = (ActionInput) data[probe]) != null) {
       if (hashCode == nextKey.getExecPathString().hashCode()
           && nextKey.getExecPathString().equals(execPathString)) {
-        return (Metadata) data[probe + 1];
+        return (FileArtifactValue) data[probe + 1];
       }
       probe = incProbe(probe);
     }
@@ -96,7 +95,7 @@
   }
 
   /** @return true if an entry was added, false if the map already contains {@code input} */
-  public boolean put(ActionInput input, Metadata metadata) {
+  public boolean put(ActionInput input, FileArtifactValue metadata) {
     Preconditions.checkNotNull(input);
     if (size * 4 >= data.length) {
       resize();
@@ -119,7 +118,7 @@
     for (int i = 0; i < oldData.length; i += 2) {
       ActionInput key = (ActionInput) oldData[i];
       if (key != null) {
-        Metadata value = (Metadata) oldData[i + 1];
+        FileArtifactValue value = (FileArtifactValue) oldData[i + 1];
         putImpl(key, value);
       }
     }
@@ -131,7 +130,7 @@
    *
    * <p>REQUIRES: there are free positions in {@link data}.
    */
-  private boolean putImpl(ActionInput key, Metadata value) {
+  private boolean putImpl(ActionInput key, FileArtifactValue value) {
     int hashCode = key.getExecPathString().hashCode();
     int probe = getProbe(hashCode);
     while (true) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java b/src/main/java/com/google/devtools/build/lib/actions/FileArtifactValue.java
similarity index 73%
rename from src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java
rename to src/main/java/com/google/devtools/build/lib/actions/FileArtifactValue.java
index b5add7c..f9f80ee 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FileArtifactValue.java
@@ -11,16 +11,13 @@
 // 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;
+package com.google.devtools.build.lib.actions;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.io.BaseEncoding;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.FileStateType;
 import com.google.devtools.build.lib.actions.cache.DigestUtils;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
@@ -35,104 +32,213 @@
 import javax.annotation.Nullable;
 
 /**
- * Stores the actual metadata data of a file. We have the following cases:
+ * State of a file system object for the execution phase.
+ *
+ * <p>This is not used by Skyframe for invalidation, it is primarily used by the action cache and
+ * the various {@link com.google.devtools.build.lib.exec.SpawnRunner} implementations.
+ *
+ * <p>We have the following cases:
  *
  * <ul>
- * <li> an ordinary file, in which case we would expect to see a digest and size;
- * <li> a directory, in which case we would expect to see an mtime;
- * <li> an intentionally omitted file which the build system is aware of but doesn't actually exist,
- *     where all access methods are unsupported;
- * <li> a "middleman marker" object, which has a null digest, 0 size, and mtime of 0.
- * <li> The "self data" of a TreeArtifact, where we would expect to see a digest representing the
- *     artifact's contents, and a size of 0.
+ *   <li>an ordinary file, in which case we would expect to see a digest and size;
+ *   <li>a directory, in which case we would expect to see an mtime;
+ *   <li>an intentionally omitted file which the build system is aware of but doesn't actually
+ *       exist, where all access methods are unsupported;
+ *   <li>a "middleman marker" object, which has a null digest, 0 size, and mtime of 0.
+ *   <li>The "self data" of a TreeArtifact, where we would expect to see a digest representing the
+ *       artifact's contents, and a size of 0.
  * </ul>
  */
-// TODO(janakr): make this an interface once JDK8 allows us to have static methods on interfaces.
-@Immutable @ThreadSafe
-public abstract class FileArtifactValue implements SkyValue, Metadata {
-  private static final class SingletonMarkerValue extends FileArtifactValue implements Singleton {
-    @Override
-    public FileStateType getType() {
-      return FileStateType.NONEXISTENT;
-    }
-
-    @Nullable
-    @Override
-    public byte[] getDigest() {
-      return null;
-    }
-
-    @Override
-    public long getSize() {
-      return 0;
-    }
-
-    @Override
-    public long getModifiedTime() {
-      return 0;
-    }
-
-    @Override
-    public boolean wasModifiedSinceDigest(Path path) throws IOException {
-      return false;
-    }
-
-    @Override
-    public String toString() {
-      return "singleton marker artifact value (" + hashCode() + ")";
-    }
-  }
-
-  private static final class OmittedFileValue extends FileArtifactValue implements Singleton {
-    @Override
-    public FileStateType getType() {
-      return FileStateType.NONEXISTENT;
-    }
-
-    @Override
-    public byte[] getDigest() {
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public long getSize() {
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public long getModifiedTime() {
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean wasModifiedSinceDigest(Path path) throws IOException {
-      return false;
-    }
-
-    @Override
-    public String toString() {
-      return "OMITTED_FILE_MARKER";
-    }
-  }
-
-  @AutoCodec static final FileArtifactValue DEFAULT_MIDDLEMAN = new SingletonMarkerValue();
+@Immutable
+@ThreadSafe
+public abstract class FileArtifactValue implements SkyValue {
+  @AutoCodec public static final FileArtifactValue DEFAULT_MIDDLEMAN = new SingletonMarkerValue();
   /** Data that marks that a file is not present on the filesystem. */
-  @VisibleForTesting @AutoCodec
-  public static final FileArtifactValue MISSING_FILE_MARKER = new SingletonMarkerValue();
+  @AutoCodec public static final FileArtifactValue MISSING_FILE_MARKER = new SingletonMarkerValue();
 
   /**
    * Represents an omitted file -- we are aware of it but it doesn't exist. All access methods are
    * unsupported.
    */
-  @AutoCodec static final FileArtifactValue OMITTED_FILE_MARKER = new OmittedFileValue();
+  @AutoCodec public static final FileArtifactValue OMITTED_FILE_MARKER = new OmittedFileValue();
 
-  @AutoCodec.VisibleForSerialization
-  @AutoCodec
-  static final class DirectoryArtifactValue extends FileArtifactValue {
+  /**
+   * Marker interface for singleton implementations of this class.
+   *
+   * <p>Needed for a correct implementation of {@code equals}.
+   */
+  public interface Singleton {}
+
+  /**
+   * The type of the underlying file system object. If it is a regular file, then it is guaranteed
+   * to have a digest. Otherwise it does not have a digest.
+   */
+  public abstract FileStateType getType();
+
+  /**
+   * Returns a digest of the content of the underlying file system object; must always return a
+   * non-null value for instances of type {@link FileStateType#REGULAR_FILE}. Otherwise may return
+   * null.
+   *
+   * <p>All instances of this interface must either have a digest or return a last-modified time.
+   * Clients should prefer using the digest for content identification (e.g., for caching), and only
+   * fall back to the last-modified time if no digest is available.
+   *
+   * <p>The return value is owned by this object and must not be modified.
+   */
+  @Nullable
+  public abstract byte[] getDigest();
+
+  /** Returns the file's size, or 0 if the underlying file system object is not a file. */
+  // TODO(ulfjack): Throw an exception if it's not a file.
+  public abstract long getSize();
+
+  /**
+   * Returns the last modified time; see the documentation of {@link #getDigest} for when this can
+   * and should be called.
+   */
+  public abstract long getModifiedTime();
+
+  /**
+   * Index used to resolve remote files.
+   *
+   * <p>0 indicates that no such information is available which can mean that it's either a local
+   * file or empty.
+   */
+  public int getLocationIndex() {
+    return 0;
+  }
+
+  /**
+   * Provides a best-effort determination whether the file was changed since the digest was
+   * computed. This method performs file system I/O, so may be expensive. It's primarily intended to
+   * avoid storing bad cache entries in an action cache. It should return true if there is a chance
+   * that the file was modified since the digest was computed. Better not upload if we are not sure
+   * that the cache entry is reliable.
+   */
+  public abstract boolean wasModifiedSinceDigest(Path path) throws IOException;
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof FileArtifactValue)) {
+      return false;
+    }
+    if ((this instanceof Singleton) || (o instanceof Singleton)) {
+      return false;
+    }
+    FileArtifactValue m = (FileArtifactValue) o;
+    if (getType() != m.getType()) {
+      return false;
+    }
+    if (getDigest() != null) {
+      return Arrays.equals(getDigest(), m.getDigest()) && getSize() == m.getSize();
+    } else {
+      return getModifiedTime() == m.getModifiedTime();
+    }
+  }
+
+  @Override
+  public int hashCode() {
+    if (this instanceof Singleton) {
+      return System.identityHashCode(this);
+    }
+    // Hash digest by content, not reference.
+    if (getDigest() != null) {
+      return 37 * Long.hashCode(getSize()) + Arrays.hashCode(getDigest());
+    } else {
+      return Long.hashCode(getModifiedTime());
+    }
+  }
+
+  public static FileArtifactValue create(Artifact artifact, FileValue fileValue)
+      throws IOException {
+    boolean isFile = fileValue.isFile();
+    FileContentsProxy proxy = getProxyFromFileStateValue(fileValue.realFileStateValue());
+    return create(
+        artifact.getPath(),
+        isFile,
+        isFile ? fileValue.getSize() : 0,
+        proxy,
+        isFile ? fileValue.getDigest() : null);
+  }
+
+  public static FileArtifactValue create(
+      Artifact artifact, FileValue fileValue, @Nullable byte[] injectedDigest) throws IOException {
+    boolean isFile = fileValue.isFile();
+    FileContentsProxy proxy = getProxyFromFileStateValue(fileValue.realFileStateValue());
+    return create(
+        artifact.getPath(), isFile, isFile ? fileValue.getSize() : 0, proxy, injectedDigest);
+  }
+
+  @VisibleForTesting
+  public static FileArtifactValue create(Artifact artifact) throws IOException {
+    return create(artifact.getPath());
+  }
+
+  @VisibleForTesting
+  public static FileArtifactValue create(Path path) throws IOException {
+    // Caution: there's a race condition between stating the file and computing the
+    // digest. We need to stat first, since we're using the stat to detect changes.
+    // We follow symlinks here to be consistent with getDigest.
+    FileStatus stat = path.stat(Symlinks.FOLLOW);
+    return create(path, stat.isFile(), stat.getSize(), FileContentsProxy.create(stat), null);
+  }
+
+  private static FileArtifactValue create(
+      Path path, boolean isFile, long size, FileContentsProxy proxy, @Nullable byte[] digest)
+      throws IOException {
+    if (!isFile) {
+      // In this case, we need to store the mtime because the action cache uses mtime for
+      // directories to determine if this artifact has changed. We want this code path to go away
+      // somehow.
+      return new DirectoryArtifactValue(path.getLastModifiedTime());
+    }
+    if (digest == null) {
+      digest = DigestUtils.getDigestOrFail(path, size);
+    }
+    Preconditions.checkState(digest != null, path);
+    return new RegularFileArtifactValue(digest, proxy, size);
+  }
+
+  public static FileArtifactValue createForVirtualActionInput(byte[] digest, long size) {
+    return new RegularFileArtifactValue(digest, /*proxy=*/ null, size);
+  }
+
+  public static FileArtifactValue createNormalFile(
+      byte[] digest, @Nullable FileContentsProxy proxy, long size) {
+    return new RegularFileArtifactValue(digest, proxy, size);
+  }
+
+  public static FileArtifactValue createNormalFile(FileValue fileValue) {
+    FileContentsProxy proxy = getProxyFromFileStateValue(fileValue.realFileStateValue());
+    return new RegularFileArtifactValue(fileValue.getDigest(), proxy, fileValue.getSize());
+  }
+
+  @VisibleForTesting
+  public static FileArtifactValue createNormalFile(byte[] digest, long size) {
+    return createNormalFile(digest, /*proxy=*/ null, size);
+  }
+
+  public static FileArtifactValue createDirectory(long mtime) {
+    return new DirectoryArtifactValue(mtime);
+  }
+
+  /**
+   * Creates a FileArtifactValue used as a 'proxy' input for other ArtifactValues. These are used in
+   * {@link com.google.devtools.build.lib.actions.ActionCacheChecker}.
+   */
+  public static FileArtifactValue createProxy(byte[] digest) {
+    Preconditions.checkNotNull(digest);
+    return createNormalFile(digest, /*proxy=*/ null, /*size=*/ 0);
+  }
+
+  private static final class DirectoryArtifactValue extends FileArtifactValue {
     private final long mtime;
 
-    @AutoCodec.VisibleForSerialization
-    DirectoryArtifactValue(long mtime) {
+    private DirectoryArtifactValue(long mtime) {
       this.mtime = mtime;
     }
 
@@ -168,15 +274,12 @@
     }
   }
 
-  @AutoCodec.VisibleForSerialization
-  @AutoCodec
-  static final class RegularFileArtifactValue extends FileArtifactValue {
+  private static final class RegularFileArtifactValue extends FileArtifactValue {
     private final byte[] digest;
     @Nullable private final FileContentsProxy proxy;
     private final long size;
 
-    @AutoCodec.VisibleForSerialization
-    RegularFileArtifactValue(byte[] digest, @Nullable FileContentsProxy proxy, long size) {
+    private RegularFileArtifactValue(byte[] digest, @Nullable FileContentsProxy proxy, long size) {
       this.digest = Preconditions.checkNotNull(digest);
       this.proxy = proxy;
       this.size = size;
@@ -239,12 +342,13 @@
     }
   }
 
-  static final class RemoteFileArtifactValue extends FileArtifactValue {
+  /** Metadata for remotely stored files. */
+  public static final class RemoteFileArtifactValue extends FileArtifactValue {
     private final byte[] digest;
     private final long size;
     private final int locationIndex;
 
-    RemoteFileArtifactValue(byte[] digest, long size, int locationIndex) {
+    public RemoteFileArtifactValue(byte[] digest, long size, int locationIndex) {
       this.digest = digest;
       this.size = size;
       this.locationIndex = locationIndex;
@@ -277,33 +381,17 @@
     }
 
     @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (!(o instanceof RemoteFileArtifactValue)) {
-        return false;
-      }
-      RemoteFileArtifactValue r = (RemoteFileArtifactValue) o;
-      return Arrays.equals(digest, r.digest) && size == r.size;
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(Arrays.hashCode(digest), size);
-    }
-
-    @Override
     public boolean wasModifiedSinceDigest(Path path) {
       throw new UnsupportedOperationException();
     }
   }
 
-  static final class InlineFileArtifactValue extends FileArtifactValue {
+  /** File stored inline in metadata. */
+  public static final class InlineFileArtifactValue extends FileArtifactValue {
     private final byte[] data;
     private final byte[] digest;
 
-    InlineFileArtifactValue(byte[] data, byte[] digest) {
+    public InlineFileArtifactValue(byte[] data, byte[] digest) {
       this.data = Preconditions.checkNotNull(data);
       this.digest = Preconditions.checkNotNull(digest);
     }
@@ -333,87 +421,11 @@
     }
 
     @Override
-    public boolean equals(Object o) {
-      if (o == this) {
-        return true;
-      }
-      if (!(o instanceof InlineFileArtifactValue)) {
-        return false;
-      }
-      InlineFileArtifactValue that = (InlineFileArtifactValue) o;
-      return Arrays.equals(digest, that.digest);
-    }
-
-    @Override
-    public int hashCode() {
-      return Arrays.hashCode(digest);
-    }
-
-    @Override
     public boolean wasModifiedSinceDigest(Path path) {
       throw new UnsupportedOperationException();
     }
   }
 
-  static FileArtifactValue create(Artifact artifact, FileValue fileValue) throws IOException {
-    boolean isFile = fileValue.isFile();
-    FileContentsProxy proxy = getProxyFromFileStateValue(fileValue.realFileStateValue());
-    return create(artifact.getPath(), isFile, isFile ? fileValue.getSize() : 0, proxy,
-        isFile ? fileValue.getDigest() : null);
-  }
-
-  static FileArtifactValue create(
-      Artifact artifact, FileValue fileValue, @Nullable byte[] injectedDigest) throws IOException {
-    boolean isFile = fileValue.isFile();
-    FileContentsProxy proxy = getProxyFromFileStateValue(fileValue.realFileStateValue());
-    return create(artifact.getPath(), isFile, isFile ? fileValue.getSize() : 0, proxy,
-        injectedDigest);
-  }
-
-  @VisibleForTesting
-  public static FileArtifactValue create(Artifact artifact) throws IOException {
-    return create(artifact.getPath());
-  }
-
-  @VisibleForTesting
-  public static FileArtifactValue create(Path path) throws IOException {
-    // Caution: there's a race condition between stating the file and computing the
-    // digest. We need to stat first, since we're using the stat to detect changes.
-    // We follow symlinks here to be consistent with getDigest.
-    FileStatus stat = path.stat(Symlinks.FOLLOW);
-    return create(path, stat.isFile(), stat.getSize(), FileContentsProxy.create(stat), null);
-  }
-
-  private static FileArtifactValue create(
-      Path path, boolean isFile, long size, FileContentsProxy proxy, @Nullable byte[] digest)
-          throws IOException {
-    if (!isFile) {
-      // In this case, we need to store the mtime because the action cache uses mtime for
-      // directories to determine if this artifact has changed. We want this code path to go away
-      // somehow (maybe by implementing FileSet in Skyframe).
-      return new DirectoryArtifactValue(path.getLastModifiedTime());
-    }
-    if (digest == null) {
-      digest = DigestUtils.getDigestOrFail(path, size);
-    }
-    Preconditions.checkState(digest != null, path);
-    return new RegularFileArtifactValue(digest, proxy, size);
-  }
-
-  public static FileArtifactValue createForVirtualActionInput(byte[] digest, long size) {
-    return new RegularFileArtifactValue(digest, /*proxy=*/ null, size);
-  }
-
-  public static FileArtifactValue createNormalFile(
-      byte[] digest, @Nullable FileContentsProxy proxy, long size) {
-    return new RegularFileArtifactValue(digest, proxy, size);
-  }
-
-  static FileArtifactValue createNormalFile(FileValue fileValue) {
-    FileContentsProxy proxy = getProxyFromFileStateValue(fileValue.realFileStateValue());
-    return new RegularFileArtifactValue(fileValue.getDigest(), proxy, fileValue.getSize());
-  }
-
   private static FileContentsProxy getProxyFromFileStateValue(FileStateValue value) {
     if (value instanceof FileStateValue.RegularFileStateValue) {
       return ((FileStateValue.RegularFileStateValue) value).getContentsProxy();
@@ -423,78 +435,68 @@
     return null;
   }
 
-  @VisibleForTesting
-  public static FileArtifactValue createNormalFile(byte[] digest, long size) {
-    return createNormalFile(digest, /*proxy=*/null, size);
-  }
-
-  public static FileArtifactValue createDirectory(long mtime) {
-    return new DirectoryArtifactValue(mtime);
-  }
-
-  /**
-   * Creates a FileArtifactValue used as a 'proxy' input for other ArtifactValues.
-   * These are used in {@link com.google.devtools.build.lib.actions.ActionCacheChecker}.
-   */
-  static FileArtifactValue createProxy(byte[] digest) {
-    Preconditions.checkNotNull(digest);
-    return createNormalFile(digest, /*proxy=*/ null, /*size=*/ 0);
-  }
-
-  @Override
-  public abstract FileStateType getType();
-
-  @Nullable
-  @Override
-  public abstract byte[] getDigest();
-
-  @Override
-  public abstract long getSize();
-
-  @Override
-  public abstract long getModifiedTime();
-
-  /**
-   * Provides a best-effort determination whether the file was changed since the digest was
-   * computed. This method performs file system I/O, so may be expensive. It's primarily intended to
-   * avoid storing bad cache entries in an action cache. It should return true if there is a chance
-   * that the file was modified since the digest was computed. Better not upload if we are not sure
-   * that the cache entry is reliable.
-   */
-  public abstract boolean wasModifiedSinceDigest(Path path) throws IOException;
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
+  private static final class SingletonMarkerValue extends FileArtifactValue implements Singleton {
+    @Override
+    public FileStateType getType() {
+      return FileStateType.NONEXISTENT;
     }
-    if (!(o instanceof Metadata)) {
+
+    @Nullable
+    @Override
+    public byte[] getDigest() {
+      return null;
+    }
+
+    @Override
+    public long getSize() {
+      return 0;
+    }
+
+    @Override
+    public long getModifiedTime() {
+      return 0;
+    }
+
+    @Override
+    public boolean wasModifiedSinceDigest(Path path) throws IOException {
       return false;
     }
-    if ((this instanceof Singleton) || (o instanceof Singleton)) {
-      return false;
-    }
-    Metadata m = (Metadata) o;
-    if (getType() != m.getType()) {
-      return false;
-    }
-    if (getDigest() != null) {
-      return Arrays.equals(getDigest(), m.getDigest()) && getSize() == m.getSize();
-    } else {
-      return getModifiedTime() == m.getModifiedTime();
+
+    @Override
+    public String toString() {
+      return "singleton marker artifact value (" + hashCode() + ")";
     }
   }
 
-  @Override
-  public int hashCode() {
-    if (this instanceof Singleton) {
-      return System.identityHashCode(this);
+  private static final class OmittedFileValue extends FileArtifactValue implements Singleton {
+    @Override
+    public FileStateType getType() {
+      return FileStateType.NONEXISTENT;
     }
-    // Hash digest by content, not reference.
-    if (getDigest() != null) {
-      return 37 * Long.hashCode(getSize()) + Arrays.hashCode(getDigest());
-    } else {
-      return Long.hashCode(getModifiedTime());
+
+    @Override
+    public byte[] getDigest() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getSize() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getModifiedTime() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean wasModifiedSinceDigest(Path path) throws IOException {
+      return false;
+    }
+
+    @Override
+    public String toString() {
+      return "OMITTED_FILE_MARKER";
     }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java b/src/main/java/com/google/devtools/build/lib/actions/FileContentsProxy.java
similarity index 95%
rename from src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java
rename to src/main/java/com/google/devtools/build/lib/actions/FileContentsProxy.java
index 2b845ed..b8a571b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FileContentsProxy.java
@@ -11,9 +11,8 @@
 // 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;
+package com.google.devtools.build.lib.actions;
 
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.vfs.FileStatus;
 import java.io.IOException;
 import java.io.Serializable;
@@ -29,7 +28,6 @@
  * So if files 'a' and 'b' initially have the same timestamp, then we would think 'b' is unchanged
  * after the user executes `mv a b` between two builds.
  */
-@AutoCodec
 public final class FileContentsProxy implements Serializable {
   private final long ctime;
   private final long nodeId;
@@ -87,4 +85,3 @@
     return String.format("ctime of %d and nodeId of %d", ctime, nodeId);
   }
 }
-
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java b/src/main/java/com/google/devtools/build/lib/actions/FileStateValue.java
similarity index 96%
rename from src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java
rename to src/main/java/com/google/devtools/build/lib/actions/FileStateValue.java
index f92e561..bc4b51a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FileStateValue.java
@@ -11,13 +11,12 @@
 // 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;
+package com.google.devtools.build.lib.actions;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Interner;
-import com.google.devtools.build.lib.actions.FileStateType;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
@@ -57,6 +56,7 @@
  */
 @VisibleForTesting
 public abstract class FileStateValue implements SkyValue {
+  public static final SkyFunctionName FILE_STATE = SkyFunctionName.create("FILE_STATE");
 
   @AutoCodec
   public static final DirectoryFileStateValue DIRECTORY_FILE_STATE_NODE =
@@ -82,9 +82,11 @@
     return createWithStatNoFollow(rootedPath, FileStatusWithDigestAdapter.adapt(stat), tsgm);
   }
 
-  static FileStateValue createWithStatNoFollow(RootedPath rootedPath,
-      FileStatusWithDigest statNoFollow, @Nullable TimestampGranularityMonitor tsgm)
-          throws InconsistentFilesystemException, IOException {
+  public static FileStateValue createWithStatNoFollow(
+      RootedPath rootedPath,
+      FileStatusWithDigest statNoFollow,
+      @Nullable TimestampGranularityMonitor tsgm)
+      throws InconsistentFilesystemException, IOException {
     Path path = rootedPath.asPath();
     if (statNoFollow.isFile()) {
       return statNoFollow.isSpecialFile()
@@ -122,14 +124,14 @@
 
     @Override
     public SkyFunctionName functionName() {
-      return SkyFunctions.FILE_STATE;
+      return FILE_STATE;
     }
   }
 
   public abstract FileStateType getType();
 
   /** Returns the target of the symlink, or throws an exception if this is not a symlink. */
-  PathFragment getSymlinkTarget() {
+  public PathFragment getSymlinkTarget() {
     throw new IllegalStateException();
   }
 
@@ -335,8 +337,7 @@
   }
 
   /** Implementation of {@link FileStateValue} for directories that exist. */
-  @AutoCodec.VisibleForSerialization
-  static final class DirectoryFileStateValue extends FileStateValue {
+  public static final class DirectoryFileStateValue extends FileStateValue {
 
     private DirectoryFileStateValue() {
     }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java b/src/main/java/com/google/devtools/build/lib/actions/FileValue.java
similarity index 92%
rename from src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java
rename to src/main/java/com/google/devtools/build/lib/actions/FileValue.java
index eeb9fc6..1fc72c1 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FileValue.java
@@ -11,12 +11,11 @@
 // 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;
+package com.google.devtools.build.lib.actions;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Interner;
-import com.google.devtools.build.lib.actions.FileStateType;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
@@ -50,6 +49,7 @@
 @Immutable
 @ThreadSafe
 public abstract class FileValue implements SkyValue {
+  public static final SkyFunctionName FILE = SkyFunctionName.create("FILE");
 
   /**
    * Exists to accommodate the control flow of {@link ActionMetadataHandler#getMetadata}.
@@ -111,17 +111,17 @@
    * example could be a build rule that copies a set of input files to the output directory, but
    * upon encountering symbolic links it can decide between copying or following them.
    */
-  PathFragment getUnresolvedLinkTarget() {
+  public PathFragment getUnresolvedLinkTarget() {
     throw new IllegalStateException(this.toString());
   }
 
-  long getSize() {
+  public long getSize() {
     Preconditions.checkState(isFile(), this);
     return realFileStateValue().getSize();
   }
 
   @Nullable
-  byte[] getDigest() {
+  public byte[] getDigest() {
     Preconditions.checkState(isFile(), this);
     return realFileStateValue().getDigest();
   }
@@ -149,15 +149,16 @@
 
     @Override
     public SkyFunctionName functionName() {
-      return SkyFunctions.FILE;
+      return FILE;
     }
   }
 
-  /**
-   * Only intended to be used by {@link FileFunction}. Should not be used for symlink cycles.
-   */
-  static FileValue value(RootedPath rootedPath, FileStateValue fileStateValue,
-                         RootedPath realRootedPath, FileStateValue realFileStateValue) {
+  /** Only intended to be used by {@link FileFunction}. Should not be used for symlink cycles. */
+  public static FileValue value(
+      RootedPath rootedPath,
+      FileStateValue fileStateValue,
+      RootedPath realRootedPath,
+      FileStateValue realFileStateValue) {
     if (rootedPath.equals(realRootedPath)) {
       Preconditions.checkState(fileStateValue.getType() != FileStateType.SYMLINK,
           "rootedPath: %s, fileStateValue: %s, realRootedPath: %s, realFileStateValue: %s",
@@ -231,13 +232,13 @@
    */
   @AutoCodec.VisibleForSerialization
   @AutoCodec
-  static class DifferentRealPathFileValue extends FileValue {
+  public static class DifferentRealPathFileValue extends FileValue {
 
     protected final RootedPath realRootedPath;
     protected final FileStateValue realFileStateValue;
 
-    @AutoCodec.VisibleForSerialization
-    DifferentRealPathFileValue(RootedPath realRootedPath, FileStateValue realFileStateValue) {
+    public DifferentRealPathFileValue(
+        RootedPath realRootedPath, FileStateValue realFileStateValue) {
       this.realRootedPath = Preconditions.checkNotNull(realRootedPath);
       this.realFileStateValue = Preconditions.checkNotNull(realFileStateValue);
     }
@@ -279,11 +280,11 @@
   /** Implementation of {@link FileValue} for files that are symlinks. */
   @VisibleForTesting
   @AutoCodec
-  static final class SymlinkFileValue extends DifferentRealPathFileValue {
+  public static final class SymlinkFileValue extends DifferentRealPathFileValue {
     private final PathFragment linkTarget;
 
     @VisibleForTesting
-    SymlinkFileValue(
+    public SymlinkFileValue(
         RootedPath realRootedPath, FileStateValue realFileStateValue, PathFragment linkTarget) {
       super(realRootedPath, realFileStateValue);
       this.linkTarget = linkTarget;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/InconsistentFilesystemException.java b/src/main/java/com/google/devtools/build/lib/actions/InconsistentFilesystemException.java
similarity index 96%
rename from src/main/java/com/google/devtools/build/lib/skyframe/InconsistentFilesystemException.java
rename to src/main/java/com/google/devtools/build/lib/actions/InconsistentFilesystemException.java
index 5397fb4..e0b0f9a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/InconsistentFilesystemException.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/InconsistentFilesystemException.java
@@ -11,7 +11,7 @@
 // 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;
+package com.google.devtools.build.lib.actions;
 
 import java.io.IOException;
 
diff --git a/src/main/java/com/google/devtools/build/lib/actions/MetadataProvider.java b/src/main/java/com/google/devtools/build/lib/actions/MetadataProvider.java
index 80d4104..60db714 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/MetadataProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/MetadataProvider.java
@@ -13,7 +13,6 @@
 // limitations under the License.
 package com.google.devtools.build.lib.actions;
 
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import java.io.IOException;
 import javax.annotation.Nullable;
 
@@ -30,21 +29,18 @@
    * calls.
    *
    * <p>Returned {@link Metadata} instance correspond to the final target of a symlink, and
-   * therefore must not have a type of
-   * {@link com.google.devtools.build.lib.actions.FileStateType#SYMLINK} themselves.
+   * therefore must not have a type of {@link FileStateType#SYMLINK} themselves.
    *
-   * The return value is owned by the cache and must not be modified.
+   * <p>The return value is owned by the cache and must not be modified.
    *
    * @param input the input to retrieve the digest for
    * @return the artifact's digest or null if digest cannot be obtained (due to artifact
-   *         non-existence, lookup errors, or any other reason)
-   *
+   *     non-existence, lookup errors, or any other reason)
    * @throws DigestOfDirectoryException in case {@code input} is a directory.
    * @throws IOException If the file cannot be digested.
-   *
    */
   @Nullable
-  Metadata getMetadata(ActionInput input) throws IOException;
+  FileArtifactValue getMetadata(ActionInput input) throws IOException;
 
   /** Looks up an input from its exec path. */
   @Nullable
diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/ActionCache.java b/src/main/java/com/google/devtools/build/lib/actions/cache/ActionCache.java
index fc21b41..c6ab560 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/cache/ActionCache.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/cache/ActionCache.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics;
 import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics.MissReason;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
@@ -79,7 +80,7 @@
     // Null iff the corresponding action does not do input discovery.
     private final List<String> files;
     // If null, md5Digest is non-null and the entry is immutable.
-    private Map<String, Metadata> mdMap;
+    private Map<String, FileArtifactValue> mdMap;
     private Md5Digest md5Digest;
     private final Md5Digest usedClientEnvDigest;
 
@@ -103,10 +104,10 @@
     }
 
     /**
-     * Adds the artifact, specified by the executable relative path and its
-     * metadata into the cache entry.
+     * Adds the artifact, specified by the executable relative path and its metadata into the cache
+     * entry.
      */
-    public void addFile(PathFragment relativePath, Metadata md) {
+    public void addFile(PathFragment relativePath, FileArtifactValue md) {
       Preconditions.checkState(mdMap != null);
       Preconditions.checkState(!isCorrupted());
       Preconditions.checkState(md5Digest == null);
diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/DigestUtils.java b/src/main/java/com/google/devtools/build/lib/actions/cache/DigestUtils.java
index d16d1ba..5e0f198 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/cache/DigestUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/cache/DigestUtils.java
@@ -19,6 +19,7 @@
 import com.google.common.cache.CacheStats;
 import com.google.common.io.BaseEncoding;
 import com.google.common.primitives.Longs;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.clock.BlazeClock;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
@@ -286,15 +287,15 @@
   }
 
   /**
-   * @param mdMap A collection of (execPath, Metadata) pairs. Values may be null.
+   * @param mdMap A collection of (execPath, FileArtifactValue) pairs. Values may be null.
    * @return an <b>order-independent</b> digest from the given "set" of (path, metadata) pairs.
    */
-  public static Md5Digest fromMetadata(Map<String, Metadata> mdMap) {
+  public static Md5Digest fromMetadata(Map<String, FileArtifactValue> mdMap) {
     byte[] result = new byte[Md5Digest.MD5_SIZE];
     // Profiling showed that MD5 engine instantiation was a hotspot, so create one instance for
     // this computation to amortize its cost.
     Fingerprint fp = new Fingerprint();
-    for (Map.Entry<String, Metadata> entry : mdMap.entrySet()) {
+    for (Map.Entry<String, FileArtifactValue> entry : mdMap.entrySet()) {
       xorWith(result, getDigest(fp, entry.getKey(), entry.getValue()));
     }
     return new Md5Digest(result);
@@ -315,7 +316,7 @@
     return new Md5Digest(result);
   }
 
-  private static byte[] getDigest(Fingerprint fp, String execPath, Metadata md) {
+  private static byte[] getDigest(Fingerprint fp, String execPath, FileArtifactValue md) {
     fp.addString(execPath);
 
     if (md == null) {
diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/Metadata.java b/src/main/java/com/google/devtools/build/lib/actions/cache/Metadata.java
deleted file mode 100644
index b9a137d..0000000
--- a/src/main/java/com/google/devtools/build/lib/actions/cache/Metadata.java
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.actions.cache;
-
-import com.google.devtools.build.lib.actions.FileStateType;
-import javax.annotation.Nullable;
-
-/**
- * An interface to represent the state of a file system object for the execution phase. This is not
- * used by Skyframe for invalidation, it is primarily used by the action cache and the various
- * {@link com.google.devtools.build.lib.exec.SpawnRunner} implementations.
- */
-public interface Metadata {
-  /**
-   * Marker interface for singleton implementations of the Metadata interface. This is only needed
-   * for a correct implementation of {@code equals}.
-   */
-  public interface Singleton {
-  }
-
-  /**
-   * The type of the underlying file system object. If it is a regular file, then it is
-   * guaranteed to have a digest. Otherwise it does not have a digest.
-   */
-  FileStateType getType();
-
-  /**
-   * Returns a digest of the content of the underlying file system object; must always return a
-   * non-null value for instances of type {@link FileStateType#REGULAR_FILE}. Otherwise may return
-   * null.
-   *
-   * <p>All instances of this interface must either have a digest or return a last-modified time.
-   * Clients should prefer using the digest for content identification (e.g., for caching), and only
-   * fall back to the last-modified time if no digest is available.
-   *
-   * <p>The return value is owned by this object and must not be modified.
-   */
-  @Nullable
-  byte[] getDigest();
-
-  /** Returns the file's size, or 0 if the underlying file system object is not a file. */
-  // TODO(ulfjack): Throw an exception if it's not a file.
-  long getSize();
-
-  /**
-   * Returns the last modified time; see the documentation of {@link #getDigest} for when this can
-   * and should be called.
-   */
-  long getModifiedTime();
-
-  /**
-   * Index used to resolve remote files.
-   *
-   * <p>0 indicates that no such information is available which can mean that it's either a local
-   * file or empty.
-   */
-  default int getLocationIndex() {
-    return 0;
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/MetadataHandler.java b/src/main/java/com/google/devtools/build/lib/actions/cache/MetadataHandler.java
index fc7e8b9..62d03fd 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/cache/MetadataHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/cache/MetadataHandler.java
@@ -16,16 +16,19 @@
 import com.google.devtools.build.lib.actions.ActionInput;
 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.vfs.FileStatus;
 import java.io.IOException;
 
 /**
- * Retrieves {@link Metadata} of {@link Artifact}s, and inserts virtual metadata as well. Some
- * methods on this interface may only be called after a call to {@link #discardOutputMetadata}.
- * Calling them before such a call results in an {@link IllegalStateException}.
+ * Retrieves {@link FileArtifactValue} of {@link Artifact}s, and inserts virtual metadata as well.
  *
- * <p>Note that implementations of this interface call chmod on output files if
- * {@link #discardOutputMetadata} has been called.
+ * <p>Some methods on this interface may only be called after a call to {@link
+ * #discardOutputMetadata}. Calling them before such a call results in an {@link
+ * IllegalStateException}.
+ *
+ * <p>Note that implementations of this interface call chmod on output files if {@link
+ * #discardOutputMetadata} has been called.
  */
 public interface MetadataHandler {
   /**
@@ -35,7 +38,7 @@
    * @return metadata instance
    * @throws IOException if metadata could not be obtained.
    */
-  Metadata getMetadata(Artifact artifact) throws IOException;
+  FileArtifactValue getMetadata(Artifact artifact) throws IOException;
 
   /** Sets digest for virtual artifacts (e.g. middlemen). {@code md5Digest} must not be null. */
   void setDigestForVirtualArtifact(Artifact artifact, Md5Digest md5Digest);
diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java b/src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java
index e4c5274..1c80cb4 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java
@@ -15,6 +15,7 @@
 
 import com.google.common.base.Preconditions;
 import com.google.devtools.build.lib.actions.ActionInput;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.protobuf.ByteString;
 import java.io.IOException;
@@ -38,11 +39,11 @@
   ByteString getBytes() throws IOException;
 
   /**
-   * Returns the Metadata for this input if available. Null otherwise.
+   * Returns the metadata for this input if available. Null otherwise.
    *
    * @throws IOException
    */
-  default Metadata getMetadata() throws IOException {
+  default FileArtifactValue getMetadata() throws IOException {
     return null;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerFunction.java
index 566e52b..6e0a8b0 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerFunction.java
@@ -16,6 +16,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.bazel.rules.workspace.MavenServerRule;
 import com.google.devtools.build.lib.packages.Rule;
@@ -24,7 +25,6 @@
 import com.google.devtools.build.lib.repository.ExternalRuleNotFoundException;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
 import com.google.devtools.build.lib.rules.repository.WorkspaceAttributeMapper;
-import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.util.Fingerprint;
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java
index fce8bf6..f245e1d 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java
@@ -18,6 +18,7 @@
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.bazel.repository.DecompressorDescriptor;
 import com.google.devtools.build.lib.bazel.repository.DecompressorValue;
 import com.google.devtools.build.lib.bazel.repository.cache.RepositoryCache.KeyType;
@@ -32,7 +33,6 @@
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
 import com.google.devtools.build.lib.rules.repository.WorkspaceAttributeMapper;
-import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.skylarkbuildapi.repository.SkylarkRepositoryContextApi;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.EvalUtils;
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
index cf61da6..c4a1d77 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
@@ -17,6 +17,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSortedSet;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.AndroidNdkCrosstools;
@@ -34,7 +35,6 @@
 import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.rules.repository.WorkspaceAttributeMapper;
 import com.google.devtools.build.lib.skyframe.DirectoryListingValue;
-import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.util.ResourceFileLoader;
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryFunction.java
index ccf3d53..7118de4 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryFunction.java
@@ -14,11 +14,11 @@
 package com.google.devtools.build.lib.bazel.rules.android;
 
 import com.google.common.collect.ImmutableSortedSet;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
 import com.google.devtools.build.lib.skyframe.DirectoryListingValue;
 import com.google.devtools.build.lib.skyframe.Dirents;
-import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
 import com.google.devtools.build.lib.vfs.Dirent;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java
index f42c575..ede9cd2 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java
@@ -22,6 +22,8 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Streams;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.packages.Rule;
@@ -29,8 +31,6 @@
 import com.google.devtools.build.lib.rules.repository.WorkspaceAttributeMapper;
 import com.google.devtools.build.lib.skyframe.DirectoryListingValue;
 import com.google.devtools.build.lib.skyframe.Dirents;
-import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.util.ResourceFileLoader;
diff --git a/src/main/java/com/google/devtools/build/lib/exec/BinTools.java b/src/main/java/com/google/devtools/build/lib/exec/BinTools.java
index c754386..651fea5 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/BinTools.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/BinTools.java
@@ -23,10 +23,9 @@
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.EnvironmentalExecException;
 import com.google.devtools.build.lib.actions.ExecException;
-import com.google.devtools.build.lib.actions.cache.Metadata;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
-import com.google.devtools.build.lib.skyframe.FileArtifactValue;
 import com.google.devtools.build.lib.vfs.Dirent;
 import com.google.devtools.build.lib.vfs.FileSystem.HashFunction;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -231,7 +230,7 @@
   public static final class PathActionInput implements VirtualActionInput {
     private final Path path;
     private final PathFragment execPath;
-    private Metadata metadata;
+    private FileArtifactValue metadata;
 
     public PathActionInput(Path path, PathFragment execPath) {
       this.path = path;
@@ -253,7 +252,7 @@
     }
 
     @Override
-    public synchronized Metadata getMetadata() throws IOException {
+    public synchronized FileArtifactValue getMetadata() throws IOException {
       // We intentionally delay hashing until it is necessary.
       if (metadata == null) {
         metadata = hash(path);
@@ -261,7 +260,7 @@
       return metadata;
     }
 
-    private static Metadata hash(Path path) throws IOException {
+    private static FileArtifactValue hash(Path path) throws IOException {
       HashFunction hashFn = path.getFileSystem().getDigestFunction();
       Hasher hasher = hashFn.getHash().newHasher();
       int bytesCopied = 0;
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SingleBuildFileCache.java b/src/main/java/com/google/devtools/build/lib/exec/SingleBuildFileCache.java
index 073e3d9..10a816c 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SingleBuildFileCache.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SingleBuildFileCache.java
@@ -19,8 +19,7 @@
 import com.google.devtools.build.lib.actions.ActionInputFileCache;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.DigestOfDirectoryException;
-import com.google.devtools.build.lib.actions.cache.Metadata;
-import com.google.devtools.build.lib.skyframe.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.Path;
 import java.io.IOException;
@@ -55,7 +54,7 @@
           .build();
 
   @Override
-  public Metadata getMetadata(ActionInput input) throws IOException {
+  public FileArtifactValue getMetadata(ActionInput input) throws IOException {
     try {
       return pathToMetadata
           .get(
@@ -95,11 +94,11 @@
   /** Container class for caching I/O around ActionInputs. */
   private static class ActionInputMetadata {
     private final ActionInput input;
-    private final Metadata metadata;
+    private final FileArtifactValue metadata;
     private final IOException exceptionOnAccess;
 
     /** Constructor for a successful lookup. */
-    ActionInputMetadata(ActionInput input, Metadata metadata) {
+    ActionInputMetadata(ActionInput input, FileArtifactValue metadata) {
       this.input = input;
       this.metadata = metadata;
       this.exceptionOnAccess = null;
@@ -112,7 +111,7 @@
       this.metadata = null;
     }
 
-    Metadata getMetadata() throws IOException {
+    FileArtifactValue getMetadata() throws IOException {
       maybeRaiseException();
       return metadata;
     }
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SpawnLogContext.java b/src/main/java/com/google/devtools/build/lib/exec/SpawnLogContext.java
index c595235..89d91e4 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SpawnLogContext.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SpawnLogContext.java
@@ -18,11 +18,11 @@
 import com.google.devtools.build.lib.actions.ActionContext;
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ExecutionStrategy;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.MetadataProvider;
 import com.google.devtools.build.lib.actions.Spawn;
 import com.google.devtools.build.lib.actions.SpawnResult;
 import com.google.devtools.build.lib.actions.Spawns;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
 import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -39,7 +39,6 @@
 import com.google.protobuf.TextFormat;
 import com.google.protobuf.TextFormat.ParseException;
 import java.io.ByteArrayOutputStream;
-
 import java.io.IOException;
 import java.time.Duration;
 import java.util.ArrayList;
@@ -228,7 +227,7 @@
       }
       // Try to access the cached metadata, otherwise fall back to local computation.
       try {
-        Metadata metadata = metadataProvider.getMetadata(input);
+        FileArtifactValue metadata = metadataProvider.getMetadata(input);
         if (metadata != null) {
           byte[] hash = metadata.getDigest();
           if (hash != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
index 311171c..382a8d2 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
@@ -40,6 +40,7 @@
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.google.devtools.build.lib.actions.FileStateValue;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
@@ -87,7 +88,6 @@
 import com.google.devtools.build.lib.query2.engine.VariableContext;
 import com.google.devtools.build.lib.skyframe.BlacklistedPackagePrefixesValue;
 import com.google.devtools.build.lib.skyframe.ContainingPackageLookupFunction;
-import com.google.devtools.build.lib.skyframe.FileStateValue;
 import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider;
 import com.google.devtools.build.lib.skyframe.PackageLookupValue;
 import com.google.devtools.build.lib.skyframe.PackageValue;
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
index 8a304cf..837d533 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
@@ -18,11 +18,11 @@
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ExecException;
 import com.google.devtools.build.lib.actions.ExecutionStrategy;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.Spawn;
 import com.google.devtools.build.lib.actions.SpawnResult;
 import com.google.devtools.build.lib.actions.SpawnResult.Status;
 import com.google.devtools.build.lib.actions.Spawns;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.events.Event;
@@ -34,7 +34,6 @@
 import com.google.devtools.build.lib.remote.util.DigestUtil;
 import com.google.devtools.build.lib.remote.util.DigestUtil.ActionKey;
 import com.google.devtools.build.lib.remote.util.TracingMetadataUtils;
-import com.google.devtools.build.lib.skyframe.FileArtifactValue;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.remoteexecution.v1test.Action;
@@ -205,7 +204,7 @@
             if (input instanceof VirtualActionInput) {
               continue;
             }
-            Metadata metadata = context.getActionInputFileCache().getMetadata(input);
+            FileArtifactValue metadata = context.getActionInputFileCache().getMetadata(input);
             if (metadata instanceof FileArtifactValue) {
               FileArtifactValue artifactValue = (FileArtifactValue) metadata;
               Path path = execRoot.getRelative(input.getExecPath());
diff --git a/src/main/java/com/google/devtools/build/lib/remote/TreeNodeRepository.java b/src/main/java/com/google/devtools/build/lib/remote/TreeNodeRepository.java
index 6ffbd13..114ce46 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/TreeNodeRepository.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/TreeNodeRepository.java
@@ -28,8 +28,8 @@
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ActionInputHelper;
 import com.google.devtools.build.lib.actions.DigestOfDirectoryException;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.MetadataProvider;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
@@ -441,7 +441,7 @@
     if (input instanceof VirtualActionInput) {
       return Preconditions.checkNotNull(virtualInputDigestCache.get(input));
     }
-    Metadata metadata = getInputMetadata(input);
+    FileArtifactValue metadata = getInputMetadata(input);
     byte[] digest = metadata.getDigest();
     if (digest == null) {
       // If the artifact does not have a digest, it is because it is a directory.
@@ -492,8 +492,8 @@
     }
   }
 
-  private Metadata getInputMetadata(ActionInput input) throws IOException {
-    Metadata metadata =
+  private FileArtifactValue getInputMetadata(ActionInput input) throws IOException {
+    FileArtifactValue metadata =
         Preconditions.checkNotNull(
             inputFileCache.getMetadata(input), "Missing metadata for: %s", input);
     if (metadata.getDigest() != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java b/src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java
index ae8b109..defc065 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java
@@ -20,9 +20,9 @@
 import com.google.common.hash.HashingOutputStream;
 import com.google.common.io.BaseEncoding;
 import com.google.devtools.build.lib.actions.ActionInput;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.MetadataProvider;
 import com.google.devtools.build.lib.actions.cache.DigestUtils;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
 import com.google.devtools.build.lib.vfs.FileSystem.HashFunction;
 import com.google.devtools.build.lib.vfs.Path;
@@ -123,7 +123,7 @@
 
   public static Digest getFromInputCache(ActionInput input, MetadataProvider cache)
       throws IOException {
-    Metadata metadata = cache.getMetadata(input);
+    FileArtifactValue metadata = cache.getMetadata(input);
     Preconditions.checkNotNull(metadata, "Input cache %s returned no value for %s", cache, input);
     Preconditions.checkNotNull(
         metadata.getDigest(),
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoSupport.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoSupport.java
index ddbe96e..512661d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FdoSupport.java
@@ -27,13 +27,13 @@
 import com.google.common.io.ByteSource;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
-import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue;
 import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
index a335d9d..904f771 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
@@ -14,11 +14,11 @@
 
 package com.google.devtools.build.lib.rules.repository;
 
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.packages.BuildFileName;
 import com.google.devtools.build.lib.packages.Rule;
-import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.lib.vfs.RootedPath;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
index bcf1597..a7111ce 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
@@ -14,12 +14,12 @@
 
 package com.google.devtools.build.lib.rules.repository;
 
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.skyframe.DirectoryListingValue;
-import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java b/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java
index 14efd5e..5e3e92f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java
@@ -14,12 +14,12 @@
 
 package com.google.devtools.build.lib.rules.repository;
 
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
 import com.google.devtools.build.lib.cmdline.LabelValidator;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
-import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.skyframe.PackageLookupValue;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Type;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
index f8f1c26..db74f31 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
@@ -16,6 +16,7 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.events.Event;
@@ -25,7 +26,6 @@
 import com.google.devtools.build.lib.repository.ExternalPackageUtil;
 import com.google.devtools.build.lib.repository.ExternalRuleNotFoundException;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
-import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue.Precomputed;
 import com.google.devtools.build.lib.util.Fingerprint;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
index 2b15ced..565780d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
@@ -18,6 +18,8 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.io.BaseEncoding;
+import com.google.devtools.build.lib.actions.FileStateValue.RegularFileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -34,8 +36,6 @@
 import com.google.devtools.build.lib.repository.ExternalPackageUtil;
 import com.google.devtools.build.lib.repository.ExternalRuleNotFoundException;
 import com.google.devtools.build.lib.skyframe.ActionEnvironmentFunction;
-import com.google.devtools.build.lib.skyframe.FileStateValue.RegularFileStateValue;
-import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.skyframe.PackageLookupValue;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Type;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
index b1f816d..df74c5e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
@@ -14,6 +14,8 @@
 
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
 import com.google.devtools.build.lib.packages.RuleClassProvider;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
index fa22da4..2ffe103 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
@@ -25,11 +25,13 @@
 import com.google.devtools.build.lib.actions.ActionCacheChecker.Token;
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionExecutionException;
+import com.google.devtools.build.lib.actions.ActionInputMap;
 import com.google.devtools.build.lib.actions.ActionLookupData;
 import com.google.devtools.build.lib.actions.ActionLookupValue;
 import com.google.devtools.build.lib.actions.ActionLookupValue.ActionLookupKey;
 import com.google.devtools.build.lib.actions.AlreadyReportedActionExecutionException;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
 import com.google.devtools.build.lib.actions.MissingInputFileException;
 import com.google.devtools.build.lib.actions.NotifyOnActionCacheHit;
@@ -42,7 +44,6 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.rules.cpp.IncludeScannable;
-import com.google.devtools.build.lib.skyframe.InputArtifactData.MutableInputArtifactData;
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.Path;
@@ -151,7 +152,7 @@
       env.getValues(state.allInputs.keysRequested);
       Preconditions.checkState(!env.valuesMissing(), "%s %s", action, state);
     }
-    Pair<MutableInputArtifactData, Map<Artifact, Collection<Artifact>>> checkedInputs = null;
+    Pair<ActionInputMap, Map<Artifact, Collection<Artifact>>> checkedInputs = null;
     try {
       // Declare deps on known inputs to action. We do this unconditionally to maintain our
       // invariant of asking for the same deps each build.
@@ -574,13 +575,13 @@
       };
 
   private static Iterable<SkyKey> newlyDiscoveredInputsToSkyKeys(
-      Iterable<Artifact> discoveredInputs, MutableInputArtifactData inputArtifactData) {
+      Iterable<Artifact> discoveredInputs, ActionInputMap inputArtifactData) {
     return Iterables.transform(
         filterKnownInputs(discoveredInputs, inputArtifactData), TO_NONMANDATORY_SKYKEY);
   }
 
   private static void addDiscoveredInputs(
-      MutableInputArtifactData inputData,
+      ActionInputMap inputData,
       Map<Artifact, Collection<Artifact>> expandedArtifacts,
       Iterable<Artifact> discoveredInputs,
       Environment env)
@@ -663,7 +664,7 @@
    * Declare dependency on all known inputs of action. Throws exception if any are known to be
    * missing. Some inputs may not yet be in the graph, in which case the builder should abort.
    */
-  private Pair<MutableInputArtifactData, Map<Artifact, Collection<Artifact>>> checkInputs(
+  private Pair<ActionInputMap, Map<Artifact, Collection<Artifact>>> checkInputs(
       Environment env,
       Action action,
       Map<SkyKey, ValueOrException2<MissingInputFileException, ActionExecutionException>> inputDeps)
@@ -676,8 +677,7 @@
     // some deps are still missing.
     boolean populateInputData = !env.valuesMissing();
     NestedSetBuilder<Cause> rootCauses = NestedSetBuilder.stableOrder();
-    MutableInputArtifactData inputArtifactData =
-        new MutableInputArtifactData(populateInputData ? inputDeps.size() : 0);
+    ActionInputMap inputArtifactData = new ActionInputMap(populateInputData ? inputDeps.size() : 0);
     Map<Artifact, Collection<Artifact>> expandedArtifacts =
         new HashMap<>(populateInputData ? 128 : 0);
 
@@ -768,8 +768,8 @@
   }
 
   private static Iterable<Artifact> filterKnownInputs(
-      Iterable<Artifact> newInputs, MutableInputArtifactData inputArtifactData) {
-    return Iterables.filter(newInputs, input -> !inputArtifactData.contains(input));
+      Iterable<Artifact> newInputs, ActionInputMap inputArtifactData) {
+    return Iterables.filter(newInputs, input -> inputArtifactData.getMetadata(input) == null);
   }
 
   /**
@@ -824,7 +824,7 @@
   private static class ContinuationState {
     AllInputs allInputs;
     /** Mutable map containing metadata for known artifacts. */
-    MutableInputArtifactData inputArtifactData = null;
+    ActionInputMap inputArtifactData = null;
 
     Map<Artifact, Collection<Artifact>> expandedArtifacts = null;
     Token token = null;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionValue.java
index a45983c..8ddb52a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionValue.java
@@ -23,6 +23,9 @@
 import com.google.devtools.build.lib.actions.ActionLookupData;
 import com.google.devtools.build.lib.actions.ActionLookupValue;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java
index cd99db9..591dd6c 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java
@@ -23,11 +23,13 @@
 import com.google.common.io.BaseEncoding;
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ActionInputFileCache;
+import com.google.devtools.build.lib.actions.ActionInputMap;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileArtifactValue.RemoteFileArtifactValue;
 import com.google.devtools.build.lib.actions.FileStateType;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
-import com.google.devtools.build.lib.skyframe.FileArtifactValue.RemoteFileArtifactValue;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -67,7 +69,7 @@
   private final Path execRootPath;
   private final ImmutableList<PathFragment> sourceRoots;
 
-  private final InputArtifactData inputArtifactData;
+  private final ActionInputMap inputArtifactData;
 
   /** exec path → artifact and metadata */
   private final HashMap<PathFragment, OptionalInputMetadata> optionalInputs;
@@ -93,7 +95,7 @@
       FileSystem delegate,
       Path execRoot,
       ImmutableList<Root> sourceRoots,
-      InputArtifactData inputArtifactData,
+      ActionInputMap inputArtifactData,
       Iterable<Artifact> allowedInputs,
       Iterable<Artifact> outputArtifacts) {
     try {
@@ -119,7 +121,7 @@
         //
         // TODO(shahan): there are no currently known cases where metadata is requested for an
         // optional source input. If there are any, we may want to stage those.
-        if (input.isSourceArtifact() || inputArtifactData.contains(input)) {
+        if (input.isSourceArtifact() || inputArtifactData.getMetadata(input) != null) {
           continue;
         }
         optionalInputs.computeIfAbsent(
@@ -157,6 +159,12 @@
     return getMetadataChecked(actionInput.getExecPath());
   }
 
+  @Override
+  @Nullable
+  public ActionInput getInput(String execPath) {
+    return inputArtifactData.getInput(execPath);
+  }
+
   // -------------------- InjectionListener Implementation --------------------
 
   @Override
@@ -265,7 +273,7 @@
   @Override
   protected void createSymbolicLink(Path linkPath, PathFragment targetFragment) throws IOException {
     PathFragment targetExecPath = asExecPath(targetFragment);
-    FileArtifactValue inputMetadata = inputArtifactData.get(targetExecPath);
+    FileArtifactValue inputMetadata = inputArtifactData.getMetadata(targetExecPath.getPathString());
     if (inputMetadata == null) {
       OptionalInputMetadata metadataHolder = optionalInputs.get(targetExecPath);
       if (metadataHolder != null) {
@@ -381,7 +389,7 @@
   @Nullable
   private FileArtifactValue getMetadataChecked(PathFragment execPath) throws IOException {
     {
-      FileArtifactValue metadata = inputArtifactData.get(execPath);
+      FileArtifactValue metadata = inputArtifactData.getMetadata(execPath.getPathString());
       if (metadata != null) {
         return metadata;
       }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionMetadataHandler.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionMetadataHandler.java
index b68930e..af2a143 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionMetadataHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionMetadataHandler.java
@@ -22,11 +22,14 @@
 import com.google.common.io.BaseEncoding;
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ActionInputHelper;
+import com.google.devtools.build.lib.actions.ActionInputMap;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.cache.Md5Digest;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.MetadataHandler;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.FileStatus;
@@ -78,7 +81,7 @@
    *
    * <p>This should never be read directly. Use {@link #getInputFileArtifactValue} instead.
    */
-  private final InputArtifactData inputArtifactData;
+  private final ActionInputMap inputArtifactData;
 
   /** FileValues for each output Artifact. */
   private final ConcurrentMap<Artifact, FileValue> outputArtifactData =
@@ -130,7 +133,7 @@
 
   @VisibleForTesting
   public ActionMetadataHandler(
-      InputArtifactData inputArtifactData,
+      ActionInputMap inputArtifactData,
       Iterable<Artifact> outputs,
       TimestampGranularityMonitor tsgm,
       ArtifactPathResolver artifactPathResolver)  {
@@ -153,7 +156,8 @@
     return artifact.isConstantMetadata() ? null : tsgm;
   }
 
-  private static Metadata metadataFromValue(FileArtifactValue value) throws FileNotFoundException {
+  private static FileArtifactValue metadataFromValue(FileArtifactValue value)
+      throws FileNotFoundException {
     if (value == FileArtifactValue.MISSING_FILE_MARKER
         || value == FileArtifactValue.OMITTED_FILE_MARKER) {
       throw new FileNotFoundException();
@@ -171,11 +175,11 @@
       return null;
     }
 
-    return inputArtifactData.get(input);
+    return inputArtifactData.getMetadata(input);
   }
 
   @Override
-  public Metadata getMetadata(Artifact artifact) throws IOException {
+  public FileArtifactValue getMetadata(Artifact artifact) throws IOException {
     FileArtifactValue value = getInputFileArtifactValue(artifact);
     if (value != null) {
       return metadataFromValue(value);
@@ -248,8 +252,8 @@
    * for normal (non-middleman) artifacts.
    */
   @Nullable
-  private Metadata maybeStoreAdditionalData(Artifact artifact, FileValue data,
-      @Nullable byte[] injectedDigest) throws IOException {
+  private FileArtifactValue maybeStoreAdditionalData(
+      Artifact artifact, FileValue data, @Nullable byte[] injectedDigest) throws IOException {
     if (!data.exists()) {
       // Nonexistent files should only occur before executing an action.
       throw new FileNotFoundException(artifact.prettyPrint() + " does not exist");
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AggregatingArtifactValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/AggregatingArtifactValue.java
index 2fb2199..e6e045b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AggregatingArtifactValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AggregatingArtifactValue.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.skyframe.SkyValue;
 import java.util.Collection;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ArtifactFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ArtifactFunction.java
index bee72a2..6913091 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ArtifactFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ArtifactFunction.java
@@ -28,6 +28,8 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
 import com.google.devtools.build.lib.actions.ArtifactOwner;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.MissingInputFileException;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.events.Event;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 79498d7..24cd665 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -21,6 +21,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Actions;
 import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.AspectResolver;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesFunction.java
index 8d96dd3..eb0f645 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesFunction.java
@@ -16,6 +16,8 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.io.CharStreams;
 import com.google.common.io.LineProcessor;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.lib.vfs.Root;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingFunction.java
index 97ee8b7..35265ce 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingFunction.java
@@ -13,6 +13,8 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.vfs.RootedPath;
 import com.google.devtools.build.skyframe.SkyFunction;
 import com.google.devtools.build.skyframe.SkyFunctionException;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
index 8d19cc1..8fc8afd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.skyframe;
 
 import com.google.common.collect.Interner;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DirtinessCheckerUtils.java b/src/main/java/com/google/devtools/build/lib/skyframe/DirtinessCheckerUtils.java
index 94a1a3b..ce4de19 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/DirtinessCheckerUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DirtinessCheckerUtils.java
@@ -13,12 +13,13 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import static com.google.devtools.build.lib.actions.FileStateValue.FILE_STATE;
 import static com.google.devtools.build.lib.skyframe.SkyFunctions.DIRECTORY_LISTING_STATE;
-import static com.google.devtools.build.lib.skyframe.SkyFunctions.FILE_STATE;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.FileStateValue;
 import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.FileType;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.Root;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
index f110ef8..7256ada 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.events.Event;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
index dc04d4b..53b1cec 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
@@ -19,6 +19,9 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import com.google.devtools.build.lib.actions.FileStateType;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.lib.vfs.Path;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileStateFunction.java
index 52876f2..8eba4cd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileStateFunction.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.devtools.build.lib.actions.FileStateValue;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.RootedPath;
 import com.google.devtools.build.skyframe.SkyFunction;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java b/src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java
index bd2f026..e154a08 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java
@@ -25,6 +25,7 @@
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.concurrent.ExecutorUtil;
 import com.google.devtools.build.lib.concurrent.Sharder;
 import com.google.devtools.build.lib.concurrent.ThrowableRecordingRunnableWrapper;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/GlobFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/GlobFunction.java
index 3dcb7f6..9d2c94a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/GlobFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/GlobFunction.java
@@ -18,6 +18,8 @@
 import com.google.common.cache.CacheBuilder;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
index 86effea..2c3ebca 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
@@ -21,6 +21,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Sets.SetView;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/InputArtifactData.java b/src/main/java/com/google/devtools/build/lib/skyframe/InputArtifactData.java
deleted file mode 100644
index 65b16d7..0000000
--- a/src/main/java/com/google/devtools/build/lib/skyframe/InputArtifactData.java
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2018 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 java.nio.charset.StandardCharsets.US_ASCII;
-
-import com.google.common.io.BaseEncoding;
-import com.google.devtools.build.lib.actions.ActionInput;
-import com.google.devtools.build.lib.actions.ActionInputMap;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import com.google.protobuf.ByteString;
-import javax.annotation.Nullable;
-
-/** A mapping from artifacts to metadata. */
-interface InputArtifactData {
-
-  boolean contains(ActionInput input);
-
-  @Nullable
-  FileArtifactValue get(ActionInput input);
-
-  @Nullable
-  FileArtifactValue get(PathFragment execPath);
-
-  @Nullable
-  ActionInput getInput(String execpath);
-
-  /**
-   * This implementation has a privileged {@link put} method supporting mutations.
-   *
-   * <p>Action execution has distinct phases where this data can be read from multiple threads. It's
-   * important that the underlying data is not modified during those phases.
-   */
-  final class MutableInputArtifactData implements InputArtifactData {
-    private final ActionInputMap inputs;
-
-    public MutableInputArtifactData(int sizeHint) {
-      this.inputs = new ActionInputMap(sizeHint);
-    }
-
-    @Override
-    public boolean contains(ActionInput input) {
-      return inputs.getMetadata(input) != null;
-    }
-
-    @Override
-    @Nullable
-    public FileArtifactValue get(ActionInput input) {
-      return (FileArtifactValue) inputs.getMetadata(input);
-    }
-
-    @Override
-    @Nullable
-    public FileArtifactValue get(PathFragment execPath) {
-      return (FileArtifactValue) inputs.getMetadata(execPath.getPathString());
-    }
-
-    @Override
-    public ActionInput getInput(String execPath) {
-      return inputs.getInput(execPath);
-    }
-
-    public void put(Artifact artifact, FileArtifactValue value) {
-      inputs.put(artifact, value);
-    }
-
-    @Override
-    public String toString() {
-      return inputs.toString();
-    }
-
-    private static ByteString toByteString(byte[] digest) {
-      return ByteString.copyFrom(
-          BaseEncoding.base16().lowerCase().encode(digest).getBytes(US_ASCII));
-    }
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunction.java
index 4c699ab..cb1012d 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunction.java
@@ -16,6 +16,8 @@
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
index 6f7a53f..635040e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
@@ -25,6 +25,8 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.clock.BlazeClock;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
index 4b26017..bc1b80a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
@@ -16,6 +16,8 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelValidator;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PerActionFileCache.java b/src/main/java/com/google/devtools/build/lib/skyframe/PerActionFileCache.java
index 54dc3a1..b566018 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PerActionFileCache.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PerActionFileCache.java
@@ -16,8 +16,9 @@
 import com.google.common.base.Preconditions;
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ActionInputFileCache;
+import com.google.devtools.build.lib.actions.ActionInputMap;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.cache.Metadata;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import javax.annotation.Nullable;
 
 /**
@@ -28,7 +29,7 @@
  * the source of truth.
  */
 class PerActionFileCache implements ActionInputFileCache {
-  private final InputArtifactData inputArtifactData;
+  private final ActionInputMap inputArtifactData;
   private final boolean missingArtifactsAllowed;
 
   /**
@@ -36,18 +37,19 @@
    * @param missingArtifactsAllowed whether to tolerate missing artifacts: can happen during input
    *     discovery.
    */
-  PerActionFileCache(InputArtifactData inputArtifactData, boolean missingArtifactsAllowed) {
+  PerActionFileCache(ActionInputMap inputArtifactData, boolean missingArtifactsAllowed) {
     this.inputArtifactData = Preconditions.checkNotNull(inputArtifactData);
     this.missingArtifactsAllowed = missingArtifactsAllowed;
   }
 
   @Nullable
   @Override
-  public Metadata getMetadata(ActionInput input) {
+  public FileArtifactValue getMetadata(ActionInput input) {
+    // TODO(shahan): is this bypass needed?
     if (!(input instanceof Artifact)) {
       return null;
     }
-    Metadata result = inputArtifactData.get(input);
+    FileArtifactValue result = inputArtifactData.getMetadata(input);
     Preconditions.checkState(missingArtifactsAllowed || result != null, "null for %s", input);
     return result;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ProcessPackageDirectory.java b/src/main/java/com/google/devtools/build/lib/skyframe/ProcessPackageDirectory.java
index 2768bde..40dce87 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ProcessPackageDirectory.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ProcessPackageDirectory.java
@@ -18,6 +18,8 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
index 2948e4e..a03f879 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
@@ -18,6 +18,9 @@
 import com.google.common.base.Verify;
 import com.google.common.collect.Collections2;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.events.Event;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalValue.java
index 8d16da6..05bce4b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalValue.java
@@ -18,6 +18,7 @@
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Interner;
+import com.google.devtools.build.lib.actions.FileStateValue;
 import com.google.devtools.build.lib.actions.FilesetTraversalParams.DirectTraversalRoot;
 import com.google.devtools.build.lib.actions.FilesetTraversalParams.PackageBoundaryMode;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RunfilesArtifactValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/RunfilesArtifactValue.java
index 8969a2c..644bd5e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RunfilesArtifactValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RunfilesArtifactValue.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.util.Pair;
 
 /** The artifacts behind a runfiles middleman. */
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
index cf49cc9..b1cd6b0 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
@@ -29,6 +29,8 @@
 import com.google.devtools.build.lib.actions.ActionKeyContext;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
 import com.google.devtools.build.lib.actions.CommandLineExpansionException;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.AnalysisProtos.ActionGraphContainer;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -313,8 +315,8 @@
   private static final ImmutableSet<SkyFunctionName> PACKAGE_LOCATOR_DEPENDENT_VALUES =
       ImmutableSet.of(
           SkyFunctions.AST_FILE_LOOKUP,
-          SkyFunctions.FILE_STATE,
-          SkyFunctions.FILE,
+          FileStateValue.FILE_STATE,
+          FileValue.FILE,
           SkyFunctions.DIRECTORY_LISTING_STATE,
           SkyFunctions.TARGET_PATTERN,
           SkyFunctions.PREPARE_DEPS_OF_PATTERN,
@@ -561,8 +563,8 @@
   private static int getNumberOfModifiedFiles(Iterable<SkyKey> modifiedValues) {
     // We are searching only for changed files, DirectoryListingValues don't depend on
     // child values, that's why they are invalidated separately
-    return Iterables.size(Iterables.filter(modifiedValues,
-        SkyFunctionName.functionIs(SkyFunctions.FILE_STATE)));
+    return Iterables.size(
+        Iterables.filter(modifiedValues, SkyFunctionName.functionIs(FileStateValue.FILE_STATE)));
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
index 7b9ca6d..0ef296c 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
@@ -27,14 +27,12 @@
       SkyFunctionName.create("CLIENT_ENVIRONMENT_VARIABLE");
   public static final SkyFunctionName ACTION_ENVIRONMENT_VARIABLE =
       SkyFunctionName.create("ACTION_ENVIRONMENT_VARIABLE");
-  public static final SkyFunctionName FILE_STATE = SkyFunctionName.create("FILE_STATE");
   public static final SkyFunctionName DIRECTORY_LISTING_STATE =
       SkyFunctionName.create("DIRECTORY_LISTING_STATE");
   public static final SkyFunctionName FILE_SYMLINK_CYCLE_UNIQUENESS =
       SkyFunctionName.create("FILE_SYMLINK_CYCLE_UNIQUENESS");
   public static final SkyFunctionName FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS =
       SkyFunctionName.create("FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS");
-  public static final SkyFunctionName FILE = SkyFunctionName.create("FILE");
   public static final SkyFunctionName DIRECTORY_LISTING =
       SkyFunctionName.create("DIRECTORY_LISTING");
   public static final SkyFunctionName PACKAGE_LOOKUP = SkyFunctionName.create("PACKAGE_LOOKUP");
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
index 5efc8cd..d0cb143 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
@@ -55,6 +55,7 @@
 import com.google.devtools.build.lib.actions.CachedActionEvent;
 import com.google.devtools.build.lib.actions.EnvironmentalExecException;
 import com.google.devtools.build.lib.actions.Executor;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
 import com.google.devtools.build.lib.actions.MapBasedActionGraph;
 import com.google.devtools.build.lib.actions.MutableActionGraph;
@@ -63,7 +64,6 @@
 import com.google.devtools.build.lib.actions.NotifyOnActionCacheHit.ActionCachedContext;
 import com.google.devtools.build.lib.actions.PackageRootResolver;
 import com.google.devtools.build.lib.actions.TargetOutOfDateException;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.MetadataHandler;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ExecutorUtil;
@@ -1266,8 +1266,8 @@
     }
 
     @Override
-    public Metadata getMetadata(ActionInput input) throws IOException {
-      Metadata metadata = perActionCache.getMetadata(input);
+    public FileArtifactValue getMetadata(ActionInput input) throws IOException {
+      FileArtifactValue metadata = perActionCache.getMetadata(input);
       return (metadata != null) && (metadata != FileArtifactValue.MISSING_FILE_MARKER)
           ? metadata
           : perBuildFileCache.getMetadata(input);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index dea750e..2b4da1b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -53,6 +53,8 @@
 import com.google.devtools.build.lib.actions.EnvironmentalExecException;
 import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.actions.FileStateType;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.ResourceManager;
 import com.google.devtools.build.lib.analysis.AnalysisProtos.ActionGraphContainer;
 import com.google.devtools.build.lib.analysis.AspectCollection;
@@ -405,14 +407,14 @@
     map.put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction());
     map.put(SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, new ClientEnvironmentFunction(clientEnv));
     map.put(SkyFunctions.ACTION_ENVIRONMENT_VARIABLE, new ActionEnvironmentFunction());
-    map.put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper));
+    map.put(FileStateValue.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper));
     map.put(SkyFunctions.DIRECTORY_LISTING_STATE,
         new DirectoryListingStateFunction(externalFilesHelper));
     map.put(SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS,
         new FileSymlinkCycleUniquenessFunction());
     map.put(SkyFunctions.FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS,
         new FileSymlinkInfiniteExpansionUniquenessFunction());
-    map.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    map.put(FileValue.FILE, new FileFunction(pkgLocator));
     map.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     map.put(
         SkyFunctions.PACKAGE_LOOKUP,
@@ -1038,7 +1040,7 @@
     Map<SkyKey, SkyValue> valuesToInject = new HashMap<>();
     for (Map.Entry<SkyKey, Delta> entry : diff.changedKeysWithNewAndOldValues().entrySet()) {
       SkyKey key = entry.getKey();
-      Preconditions.checkState(key.functionName().equals(SkyFunctions.FILE_STATE), key);
+      Preconditions.checkState(key.functionName().equals(FileStateValue.FILE_STATE), key);
       RootedPath rootedPath = (RootedPath) key.argument();
       Delta delta = entry.getValue();
       FileStateValue oldValue = (FileStateValue) delta.getOldValue();
@@ -1074,7 +1076,7 @@
       }
     }
     for (SkyKey key : diff.changedKeysWithoutNewValues()) {
-      Preconditions.checkState(key.functionName().equals(SkyFunctions.FILE_STATE), key);
+      Preconditions.checkState(key.functionName().equals(FileStateValue.FILE_STATE), key);
       RootedPath rootedPath = (RootedPath) key.argument();
       valuesToInvalidate.add(parentDirectoryListingStateKey(rootedPath));
     }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeIncrementalBuildMonitor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeIncrementalBuildMonitor.java
index 462e51f..3ab37e2 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeIncrementalBuildMonitor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeIncrementalBuildMonitor.java
@@ -16,6 +16,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.actions.ChangedFilesMessage;
+import com.google.devtools.build.lib.actions.FileStateValue;
 import com.google.devtools.build.lib.concurrent.ThreadSafety;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.lib.vfs.RootedPath;
@@ -37,7 +38,7 @@
 
   public void accrue(Iterable<SkyKey> invalidatedValues) {
     for (SkyKey skyKey : invalidatedValues) {
-      if (skyKey.functionName().equals(SkyFunctions.FILE_STATE)) {
+      if (skyKey.functionName().equals(FileStateValue.FILE_STATE)) {
         RootedPath file = (RootedPath) skyKey.argument();
         maybeAddFile(file.getRootRelativePath());
       }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageLoaderWithValueEnvironment.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageLoaderWithValueEnvironment.java
index 9903969..a674abb 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageLoaderWithValueEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageLoaderWithValueEnvironment.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
index 93f7596..9dc5ed8 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
@@ -26,6 +26,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java
index 1758fb3..234eb6c 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TreeArtifactValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/TreeArtifactValue.java
index 4cf0014..b7ca908 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TreeArtifactValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TreeArtifactValue.java
@@ -21,8 +21,8 @@
 import com.google.common.collect.Maps;
 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.actions.cache.DigestUtils;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -61,7 +61,7 @@
    * and their corresponding FileArtifactValues.
    */
   static TreeArtifactValue create(Map<TreeFileArtifact, FileArtifactValue> childFileValues) {
-    Map<String, Metadata> digestBuilder =
+    Map<String, FileArtifactValue> digestBuilder =
         Maps.newHashMapWithExpectedSize(childFileValues.size());
     for (Map.Entry<TreeFileArtifact, FileArtifactValue> e : childFileValues.entrySet()) {
       digestBuilder.put(e.getKey().getParentRelativePath().getPathString(), e.getValue());
@@ -76,7 +76,7 @@
     return FileArtifactValue.createProxy(digest);
   }
 
-  Metadata getMetadata() {
+  FileArtifactValue getMetadata() {
     return getSelfData();
   }
 
@@ -129,57 +129,57 @@
   }
 
   /**
-   * A TreeArtifactValue that represents a missing TreeArtifact.
-   * This is occasionally useful because Java's concurrent collections disallow null members.
+   * A TreeArtifactValue that represents a missing TreeArtifact. This is occasionally useful because
+   * Java's concurrent collections disallow null members.
    */
-  static final TreeArtifactValue MISSING_TREE_ARTIFACT = new TreeArtifactValue(null,
-      ImmutableMap.<TreeFileArtifact, FileArtifactValue>of()) {
-    @Override
-    FileArtifactValue getSelfData() {
-      throw new UnsupportedOperationException();
-    }
+  static final TreeArtifactValue MISSING_TREE_ARTIFACT =
+      new TreeArtifactValue(null, ImmutableMap.<TreeFileArtifact, FileArtifactValue>of()) {
+        @Override
+        FileArtifactValue getSelfData() {
+          throw new UnsupportedOperationException();
+        }
 
-    @Override
-    Iterable<TreeFileArtifact> getChildren() {
-      throw new UnsupportedOperationException();
-    }
+        @Override
+        Iterable<TreeFileArtifact> getChildren() {
+          throw new UnsupportedOperationException();
+        }
 
-    @Override
-    Map<TreeFileArtifact, FileArtifactValue> getChildValues() {
-      throw new UnsupportedOperationException();
-    }
+        @Override
+        Map<TreeFileArtifact, FileArtifactValue> getChildValues() {
+          throw new UnsupportedOperationException();
+        }
 
-    @Override
-    Metadata getMetadata() {
-      throw new UnsupportedOperationException();
-    }
+        @Override
+        FileArtifactValue getMetadata() {
+          throw new UnsupportedOperationException();
+        }
 
-    @Override
-    Set<PathFragment> getChildPaths() {
-      throw new UnsupportedOperationException();
-    }
+        @Override
+        Set<PathFragment> getChildPaths() {
+          throw new UnsupportedOperationException();
+        }
 
-    @Nullable
-    @Override
-    byte[] getDigest() {
-      throw new UnsupportedOperationException();
-    }
+        @Nullable
+        @Override
+        byte[] getDigest() {
+          throw new UnsupportedOperationException();
+        }
 
-    @Override
-    public int hashCode() {
-      return 24; // my favorite number
-    }
+        @Override
+        public int hashCode() {
+          return 24; // my favorite number
+        }
 
-    @Override
-    public boolean equals(Object other) {
-      return this == other;
-    }
+        @Override
+        public boolean equals(Object other) {
+          return this == other;
+        }
 
-    @Override
-    public String toString() {
-      return "MISSING_TREE_ARTIFACT";
-    }
-  };
+        @Override
+        public String toString() {
+          return "MISSING_TREE_ARTIFACT";
+        }
+      };
 
   private static void explodeDirectory(Artifact treeArtifact,
       PathFragment pathToExplode, ImmutableSet.Builder<PathFragment> valuesBuilder)
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunction.java
index a36fd32..a8d14ca 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunction.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.skyframe;
 
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
 import com.google.devtools.build.lib.packages.RuleClassProvider;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java b/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
index d8f4cb8..d0f74c5 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
@@ -23,6 +23,8 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.eventbus.EventBus;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.clock.BlazeClock;
@@ -388,12 +390,12 @@
     ImmutableMap.Builder<SkyFunctionName, SkyFunction> builder = ImmutableMap.builder();
     builder
         .put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction())
-        .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper))
+        .put(FileStateValue.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper))
         .put(SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS, new FileSymlinkCycleUniquenessFunction())
         .put(
             SkyFunctions.FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS,
             new FileSymlinkInfiniteExpansionUniquenessFunction())
-        .put(SkyFunctions.FILE, new FileFunction(pkgLocatorRef))
+        .put(FileValue.FILE, new FileFunction(pkgLocatorRef))
         .put(
             SkyFunctions.PACKAGE_LOOKUP,
             new PackageLookupFunction(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/packages/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/packages/BUILD
index 7cb108a..1fc1d17 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/packages/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/packages/BUILD
@@ -17,6 +17,7 @@
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:io",
         "//src/main/java/com/google/devtools/build/lib:packages-internal",
+        "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/cache",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/downloader",
         "//src/main/java/com/google/devtools/build/lib/clock",
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerFilesHash.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerFilesHash.java
index ddc7da7..f35823a 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerFilesHash.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerFilesHash.java
@@ -23,8 +23,8 @@
 import com.google.devtools.build.lib.actions.ActionInputHelper;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.Spawn;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.io.IOException;
 import java.nio.charset.Charset;
@@ -72,7 +72,7 @@
       for (Map.Entry<PathFragment, Artifact> mapping : rootAndMappings.getValue().entrySet()) {
         Artifact localArtifact = mapping.getValue();
         if (localArtifact != null) {
-          Metadata metadata = actionInputFileCache.getMetadata(localArtifact);
+          FileArtifactValue metadata = actionInputFileCache.getMetadata(localArtifact);
           if (metadata.getType().isFile()) {
             workerFilesMap.put(
                 root.getRelative(mapping.getKey()),
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index 0e83b59..29b35fd 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -1487,6 +1487,7 @@
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:io",
         "//src/main/java/com/google/devtools/build/lib:packages-internal",
+        "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/vfs",
         "//src/main/java/com/google/devtools/build/skyframe",
         "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
diff --git a/src/test/java/com/google/devtools/build/lib/actions/ActionCacheCheckerTest.java b/src/test/java/com/google/devtools/build/lib/actions/ActionCacheCheckerTest.java
index 87578eb..a84efb3 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/ActionCacheCheckerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/ActionCacheCheckerTest.java
@@ -22,7 +22,6 @@
 import com.google.devtools.build.lib.actions.cache.ActionCache;
 import com.google.devtools.build.lib.actions.cache.CompactPersistentActionCache;
 import com.google.devtools.build.lib.actions.cache.Md5Digest;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.MetadataHandler;
 import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics;
 import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics.MissDetail;
@@ -32,7 +31,6 @@
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil.MissDetailsBuilder;
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil.NullAction;
 import com.google.devtools.build.lib.clock.Clock;
-import com.google.devtools.build.lib.skyframe.FileArtifactValue;
 import com.google.devtools.build.lib.testutil.ManualClock;
 import com.google.devtools.build.lib.testutil.Scratch;
 import com.google.devtools.build.lib.util.Fingerprint;
@@ -335,7 +333,7 @@
   /** A fake metadata handler that is able to obtain metadata from the file system. */
   private static class FakeMetadataHandler extends FakeMetadataHandlerBase {
     @Override
-    public Metadata getMetadata(Artifact artifact) throws IOException {
+    public FileArtifactValue getMetadata(Artifact artifact) throws IOException {
       return FileArtifactValue.create(artifact);
     }
 
diff --git a/src/test/java/com/google/devtools/build/lib/actions/ActionInputMapTest.java b/src/test/java/com/google/devtools/build/lib/actions/ActionInputMapTest.java
index 5690fec..2f3313e 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/ActionInputMapTest.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/ActionInputMapTest.java
@@ -16,7 +16,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static java.nio.charset.StandardCharsets.US_ASCII;
 
-import com.google.devtools.build.lib.actions.cache.Metadata;
+import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -160,7 +160,7 @@
     }
   }
 
-  private static class TestMetadata implements Metadata {
+  private static class TestMetadata extends FileArtifactValue {
     private final int id;
 
     public TestMetadata(int id) {
@@ -188,6 +188,11 @@
     }
 
     @Override
+    public boolean wasModifiedSinceDigest(Path path) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
     @SuppressWarnings("EqualsHashCode")
     public boolean equals(Object o) {
       if (!(o instanceof TestMetadata)) {
diff --git a/src/test/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCacheTest.java b/src/test/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCacheTest.java
index 90eec0c6..54b4d9d 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCacheTest.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCacheTest.java
@@ -17,7 +17,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.devtools.build.lib.skyframe.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.testutil.ManualClock;
 import com.google.devtools.build.lib.testutil.Scratch;
 import com.google.devtools.build.lib.vfs.Path;
diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
index bad5203..013f57e 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
@@ -46,11 +46,11 @@
 import com.google.devtools.build.lib.actions.ArtifactResolver;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
 import com.google.devtools.build.lib.actions.Executor;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.MutableActionGraph;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.PackageRootResolver;
 import com.google.devtools.build.lib.actions.cache.Md5Digest;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.cache.MetadataHandler;
 import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics.MissDetail;
 import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics.MissReason;
@@ -709,7 +709,7 @@
    */
   public static class FakeMetadataHandlerBase implements MetadataHandler {
     @Override
-    public Metadata getMetadata(Artifact artifact) throws IOException {
+    public FileArtifactValue getMetadata(Artifact artifact) throws IOException {
       throw new UnsupportedOperationException();
     }
 
diff --git a/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java b/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java
index 211dbe9..67be7fa 100644
--- a/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java
@@ -27,12 +27,12 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
 import com.google.devtools.build.lib.actions.EmptyRunfilesSupplier;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
 import com.google.devtools.build.lib.actions.RunfilesSupplier;
 import com.google.devtools.build.lib.analysis.Runfiles;
 import com.google.devtools.build.lib.analysis.RunfilesSupplierImpl;
 import com.google.devtools.build.lib.exec.util.FakeActionInputFileCache;
-import com.google.devtools.build.lib.skyframe.FileArtifactValue;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
diff --git a/src/test/java/com/google/devtools/build/lib/exec/util/FakeActionInputFileCache.java b/src/test/java/com/google/devtools/build/lib/exec/util/FakeActionInputFileCache.java
index 9c215fc..6eb2668 100644
--- a/src/test/java/com/google/devtools/build/lib/exec/util/FakeActionInputFileCache.java
+++ b/src/test/java/com/google/devtools/build/lib/exec/util/FakeActionInputFileCache.java
@@ -16,24 +16,24 @@
 import com.google.common.base.Preconditions;
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ActionInputFileCache;
-import com.google.devtools.build.lib.actions.cache.Metadata;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
 /** A fake implementation of the {@link ActionInputFileCache} interface. */
 public final class FakeActionInputFileCache implements ActionInputFileCache {
-  private final Map<ActionInput, Metadata> inputs = new HashMap<>();
+  private final Map<ActionInput, FileArtifactValue> inputs = new HashMap<>();
 
   public FakeActionInputFileCache() {
   }
 
-  public void put(ActionInput artifact, Metadata metadata) {
+  public void put(ActionInput artifact, FileArtifactValue metadata) {
     inputs.put(artifact, metadata);
   }
 
   @Override
-  public Metadata getMetadata(ActionInput input) throws IOException {
+  public FileArtifactValue getMetadata(ActionInput input) throws IOException {
     return Preconditions.checkNotNull(inputs.get(input));
   }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/remote/FakeActionInputFileCache.java b/src/test/java/com/google/devtools/build/lib/remote/FakeActionInputFileCache.java
index 26cc290..729eeb2 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/FakeActionInputFileCache.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/FakeActionInputFileCache.java
@@ -19,10 +19,9 @@
 import com.google.common.hash.HashCode;
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ActionInputFileCache;
-import com.google.devtools.build.lib.actions.cache.Metadata;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileContentsProxy;
 import com.google.devtools.build.lib.remote.util.DigestUtil;
-import com.google.devtools.build.lib.skyframe.FileArtifactValue;
-import com.google.devtools.build.lib.skyframe.FileContentsProxy;
 import com.google.devtools.build.lib.vfs.FileStatus;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
@@ -43,7 +42,7 @@
   }
 
   @Override
-  public Metadata getMetadata(ActionInput input) throws IOException {
+  public FileArtifactValue getMetadata(ActionInput input) throws IOException {
     String hexDigest = Preconditions.checkNotNull(cas.get(input), input);
     Path path = execRoot.getRelative(input.getExecPath());
     FileStatus stat = path.stat(Symlinks.FOLLOW);
diff --git a/src/test/java/com/google/devtools/build/lib/repository/ExternalPackageUtilTest.java b/src/test/java/com/google/devtools/build/lib/repository/ExternalPackageUtilTest.java
index 4655acc..709d9dc 100644
--- a/src/test/java/com/google/devtools/build/lib/repository/ExternalPackageUtilTest.java
+++ b/src/test/java/com/google/devtools/build/lib/repository/ExternalPackageUtilTest.java
@@ -20,6 +20,8 @@
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.analysis.util.AnalysisMock;
@@ -110,10 +112,10 @@
             CrossRepositoryLabelViolationStrategy.ERROR,
             BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY));
     skyFunctions.put(
-        SkyFunctions.FILE_STATE,
+        FileStateValue.FILE_STATE,
         new FileStateFunction(
             new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
-    skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
     RuleClassProvider ruleClassProvider = analysisMock.createRuleClassProvider();
     skyFunctions.put(SkyFunctions.WORKSPACE_AST, new WorkspaceASTFunction(ruleClassProvider));
     skyFunctions.put(
diff --git a/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java b/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java
index 78f2d01..8bde0bc 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java
@@ -18,6 +18,8 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
@@ -98,10 +100,10 @@
         new InMemoryMemoizingEvaluator(
             ImmutableMap.<SkyFunctionName, SkyFunction>builder()
                 .put(
-                    SkyFunctions.FILE_STATE,
+                    FileStateValue.FILE_STATE,
                     new FileStateFunction(
                         new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper))
-                .put(SkyFunctions.FILE, new FileFunction(pkgLocator))
+                .put(FileValue.FILE, new FileFunction(pkgLocator))
                 .put(SkyFunctions.REPOSITORY_DIRECTORY, delegatorFunction)
                 .put(
                     SkyFunctions.PACKAGE,
diff --git a/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryFunctionTest.java b/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryFunctionTest.java
index c767d51..f399544 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryFunctionTest.java
@@ -18,15 +18,15 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.io.BaseEncoding;
+import com.google.devtools.build.lib.actions.FileContentsProxy;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileStateValue.RegularFileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.FileValue.RegularFileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.packages.Rule;
-import com.google.devtools.build.lib.skyframe.FileContentsProxy;
-import com.google.devtools.build.lib.skyframe.FileStateValue;
-import com.google.devtools.build.lib.skyframe.FileStateValue.RegularFileStateValue;
-import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.FileValue.RegularFileValue;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionFunctionTest.java
index 9703fb4..ef30031 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionFunctionTest.java
@@ -33,6 +33,7 @@
 import com.google.devtools.build.lib.actions.ArtifactOwner;
 import com.google.devtools.build.lib.actions.ArtifactPrefixConflictException;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
index 4615783..2b137ed 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
@@ -14,7 +14,7 @@
 package com.google.devtools.build.lib.skyframe;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.google.devtools.build.lib.skyframe.FileArtifactValue.create;
+import static com.google.devtools.build.lib.actions.FileArtifactValue.create;
 import static org.junit.Assert.fail;
 
 import com.google.common.collect.ImmutableList;
@@ -33,6 +33,8 @@
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
 import com.google.devtools.build.lib.actions.BasicActionLookupValue;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.MissingInputFileException;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java
index c0c2d73..aa73683 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java
@@ -19,6 +19,8 @@
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
 import com.google.devtools.build.lib.actions.ActionKeyContext;
 import com.google.devtools.build.lib.actions.ActionLookupValue.ActionLookupKey;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
@@ -91,10 +93,10 @@
         new InMemoryMemoizingEvaluator(
             ImmutableMap.<SkyFunctionName, SkyFunction>builder()
                 .put(
-                    SkyFunctions.FILE_STATE,
+                    FileStateValue.FILE_STATE,
                     new FileStateFunction(
                         new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper))
-                .put(SkyFunctions.FILE, new FileFunction(pkgLocator))
+                .put(FileValue.FILE, new FileFunction(pkgLocator))
                 .put(SkyFunctions.ARTIFACT, new ArtifactFunction())
                 .put(SkyFunctions.ACTION_EXECUTION, new SimpleActionExecutionFunction())
                 .put(
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupFunctionTest.java
index 100b086..4c845af 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupFunctionTest.java
@@ -19,6 +19,8 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.testing.EqualsTester;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.analysis.util.AnalysisMock;
@@ -108,9 +110,11 @@
         new BlacklistedPackagePrefixesFunction(
             /*hardcodedBlacklistedPackagePrefixes=*/ ImmutableSet.of(),
             /*additionalBlacklistedPackagePrefixesFile=*/ PathFragment.EMPTY_FRAGMENT));
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
-        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
-    skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    skyFunctions.put(
+        FileStateValue.FILE_STATE,
+        new FileStateFunction(
+            new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
+    skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     skyFunctions.put(
         SkyFunctions.DIRECTORY_LISTING_STATE,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileArtifactValueTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileArtifactValueTest.java
index 87e4bd2..92ed596 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FileArtifactValueTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileArtifactValueTest.java
@@ -14,11 +14,12 @@
 package com.google.devtools.build.lib.skyframe;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.google.devtools.build.lib.skyframe.FileArtifactValue.create;
+import static com.google.devtools.build.lib.actions.FileArtifactValue.create;
 import static org.junit.Assert.fail;
 
 import com.google.common.io.BaseEncoding;
 import com.google.common.testing.EqualsTester;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
 import com.google.devtools.build.lib.testutil.ManualClock;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileContentsProxyTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileContentsProxyTest.java
index 0ca3da5..db4cdc0 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FileContentsProxyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileContentsProxyTest.java
@@ -16,6 +16,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.testing.EqualsTester;
+import com.google.devtools.build.lib.actions.FileContentsProxy;
 import com.google.devtools.build.lib.vfs.FileStatus;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
index 926d63b..390436b 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
@@ -30,6 +30,9 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.testing.EqualsTester;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.clock.BlazeClock;
@@ -140,7 +143,7 @@
         new InMemoryMemoizingEvaluator(
             ImmutableMap.<SkyFunctionName, SkyFunction>builder()
                 .put(
-                    SkyFunctions.FILE_STATE,
+                    FileStateValue.FILE_STATE,
                     new FileStateFunction(
                         new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper))
                 .put(
@@ -149,7 +152,7 @@
                 .put(
                     SkyFunctions.FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS,
                     new FileSymlinkInfiniteExpansionUniquenessFunction())
-                .put(SkyFunctions.FILE, new FileFunction(pkgLocatorRef))
+                .put(FileValue.FILE, new FileFunction(pkgLocatorRef))
                 .put(
                     SkyFunctions.PACKAGE,
                     new PackageFunction(null, null, null, null, null, null, null))
@@ -765,7 +768,7 @@
                 Iterables.transform(
                     Iterables.filter(
                         graph.getValues().keySet(),
-                        SkyFunctionName.functionIs(SkyFunctions.FILE_STATE)),
+                        SkyFunctionName.functionIs(FileStateValue.FILE_STATE)),
                     new Function<SkyKey, Object>() {
                       @Override
                       public Object apply(SkyKey skyKey) {
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileStateValueTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileStateValueTest.java
index 36f8d24..f3b3c58 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FileStateValueTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileStateValueTest.java
@@ -14,6 +14,8 @@
 
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.devtools.build.lib.actions.FileContentsProxy;
+import com.google.devtools.build.lib.actions.FileStateValue;
 import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import org.junit.Test;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileValueTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileValueTest.java
index c6d0a34..2b059ab 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FileValueTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileValueTest.java
@@ -14,6 +14,8 @@
 
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.skyframe.serialization.testutils.FsUtils;
 import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester;
 import com.google.devtools.build.lib.vfs.FileSystem;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FilesetEntryFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FilesetEntryFunctionTest.java
index 02088a9..df0320f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FilesetEntryFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FilesetEntryFunctionTest.java
@@ -26,6 +26,8 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
 import com.google.devtools.build.lib.actions.FilesetTraversalParams;
 import com.google.devtools.build.lib.actions.FilesetTraversalParams.PackageBoundaryMode;
@@ -101,9 +103,11 @@
 
     Map<SkyFunctionName, SkyFunction> skyFunctions = new HashMap<>();
 
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
-        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
-    skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    skyFunctions.put(
+        FileStateValue.FILE_STATE,
+        new FileStateFunction(
+            new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
+    skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     skyFunctions.put(
         SkyFunctions.DIRECTORY_LISTING_STATE,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
index f0112d4..385b738 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
@@ -30,6 +30,9 @@
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
 import com.google.devtools.build.lib.actions.ArtifactOwner;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.util.TestAction;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
@@ -117,9 +120,11 @@
             TestConstants.PRODUCT_NAME);
     ExternalFilesHelper externalFilesHelper = ExternalFilesHelper.createForTesting(
         pkgLocator, ExternalFileAction.DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS, directories);
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
-        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
-    skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    skyFunctions.put(
+        FileStateValue.FILE_STATE,
+        new FileStateFunction(
+            new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
+    skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(
         SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS, new FileSymlinkCycleUniquenessFunction());
     skyFunctions.put(
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
index 167672a..7d118c6 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
@@ -24,6 +24,9 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.testing.EqualsTester;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.analysis.util.AnalysisMock;
@@ -160,10 +163,10 @@
             /*hardcodedBlacklistedPackagePrefixes=*/ ImmutableSet.of(),
             /*additionalBlacklistedPackagePrefixesFile=*/ PathFragment.EMPTY_FRAGMENT));
     skyFunctions.put(
-        SkyFunctions.FILE_STATE,
+        FileStateValue.FILE_STATE,
         new FileStateFunction(
             new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
-    skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     skyFunctions.put(
         SkyFunctions.DIRECTORY_LISTING_STATE,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunctionTest.java
index 3e457ba..30524ff 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunctionTest.java
@@ -18,6 +18,8 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.analysis.util.AnalysisMock;
@@ -90,10 +92,10 @@
             CrossRepositoryLabelViolationStrategy.ERROR,
             BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY));
     skyFunctions.put(
-        SkyFunctions.FILE_STATE,
+        FileStateValue.FILE_STATE,
         new FileStateFunction(
             new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
-    skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     skyFunctions.put(
         SkyFunctions.DIRECTORY_LISTING_STATE,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
index db71eda..b6681d0 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
@@ -22,6 +22,8 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.clock.BlazeClock;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -570,7 +572,7 @@
     getSkyframeExecutor()
         .invalidate(
             Predicates.equalTo(
-                com.google.devtools.build.lib.skyframe.FileStateValue.key(
+                FileStateValue.key(
                     RootedPath.toRootedPath(
                         Root.fromPath(workspacePath.getParentDirectory()),
                         PathFragment.create(workspacePath.getBaseName())))));
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PackageLookupFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PackageLookupFunctionTest.java
index 4d63399..7562559 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/PackageLookupFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PackageLookupFunctionTest.java
@@ -21,6 +21,8 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.testing.EqualsTester;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ServerDirectories;
 import com.google.devtools.build.lib.analysis.util.AnalysisMock;
@@ -117,9 +119,11 @@
     skyFunctions.put(
         SkyFunctions.PACKAGE,
         new PackageFunction(null, null, null, null, null, null, null));
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
-        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
-    skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    skyFunctions.put(
+        FileStateValue.FILE_STATE,
+        new FileStateFunction(
+            new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
+    skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     skyFunctions.put(
         SkyFunctions.DIRECTORY_LISTING_STATE,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunctionTest.java
index 6e62d1a..6ccaa19 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunctionTest.java
@@ -28,6 +28,9 @@
 import com.google.common.collect.Sets;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.FilesetTraversalParams.DirectTraversalRoot;
 import com.google.devtools.build.lib.actions.FilesetTraversalParams.PackageBoundaryMode;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
@@ -112,9 +115,10 @@
 
     ConfiguredRuleClassProvider ruleClassProvider = analysisMock.createRuleClassProvider();
     Map<SkyFunctionName, SkyFunction> skyFunctions = new HashMap<>();
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
-        new AtomicReference<>(), externalFilesHelper));
-    skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
+    skyFunctions.put(
+        FileStateValue.FILE_STATE,
+        new FileStateFunction(new AtomicReference<>(), externalFilesHelper));
+    skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     skyFunctions.put(
         SkyFunctions.DIRECTORY_LISTING_STATE,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeAwareActionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeAwareActionTest.java
index 00cdc24..3bd08d3 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeAwareActionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeAwareActionTest.java
@@ -29,6 +29,7 @@
 import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Executor;
+import com.google.devtools.build.lib.actions.FileStateValue;
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
 import com.google.devtools.build.lib.actions.util.DummyExecutor;
 import com.google.devtools.build.lib.testutil.TimestampGranularityUtils;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
index e17e673..2b16cdf 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
@@ -44,6 +44,8 @@
 import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.actions.BuildFailedException;
 import com.google.devtools.build.lib.actions.Executor;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.ResourceManager;
 import com.google.devtools.build.lib.actions.ResourceSet;
@@ -203,8 +205,8 @@
     final InMemoryMemoizingEvaluator evaluator =
         new InMemoryMemoizingEvaluator(
             ImmutableMap.<SkyFunctionName, SkyFunction>builder()
-                .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgmRef, externalFilesHelper))
-                .put(SkyFunctions.FILE, new FileFunction(pkgLocator))
+                .put(FileStateValue.FILE_STATE, new FileStateFunction(tsgmRef, externalFilesHelper))
+                .put(FileValue.FILE, new FileFunction(pkgLocator))
                 .put(SkyFunctions.ARTIFACT, new ArtifactFunction())
                 .put(
                     SkyFunctions.ACTION_EXECUTION,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
index 54a9302..1b9b6bc 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
@@ -34,10 +34,11 @@
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
 import com.google.devtools.build.lib.actions.BasicActionLookupValue;
+import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.actions.MissingInputFileException;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.cache.DigestUtils;
-import com.google.devtools.build.lib.actions.cache.Metadata;
 import com.google.devtools.build.lib.actions.util.TestAction.DummyAction;
 import com.google.devtools.build.lib.events.NullEventHandler;
 import com.google.devtools.build.lib.vfs.FileStatus;
@@ -101,9 +102,9 @@
     // Assertions about digest. As of this writing this logic is essentially the same
     // as that in TreeArtifact, but it's good practice to unit test anyway to guard against
     // breaking changes.
-    Map<String, Metadata> digestBuilder = new HashMap<>();
+    Map<String, FileArtifactValue> digestBuilder = new HashMap<>();
     for (PathFragment child : children) {
-      Metadata subdigest = FileArtifactValue.create(tree.getPath().getRelative(child));
+      FileArtifactValue subdigest = FileArtifactValue.create(tree.getPath().getRelative(child));
       digestBuilder.put(child.getPathString(), subdigest);
     }
     assertThat(DigestUtils.fromMetadata(digestBuilder).getDigestBytesUnsafe())
@@ -114,7 +115,7 @@
   @Test
   public void testEmptyTreeArtifacts() throws Exception {
     TreeArtifactValue value = doTestTreeArtifacts(ImmutableList.<PathFragment>of());
-    // Additional test, only for this test method: we expect the Metadata is equal to
+    // Additional test, only for this test method: we expect the FileArtifactValue is equal to
     // the digest [0, 0, ...]
     assertThat(value.getMetadata().getDigest()).isEqualTo(value.getDigest());
     // Java zero-fills arrays.
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunctionTest.java
index ece3f59..b06f6c7 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunctionTest.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.skyframe.WorkspaceFileFunctionTest.FakeFileValue;
@@ -67,7 +68,7 @@
 
   private SkyFunction.Environment getEnv() throws InterruptedException {
     SkyFunction.Environment env = Mockito.mock(SkyFunction.Environment.class);
-    Mockito.when(env.getValue(Matchers.argThat(new SkyKeyMatchers(SkyFunctions.FILE))))
+    Mockito.when(env.getValue(Matchers.argThat(new SkyKeyMatchers(FileValue.FILE))))
         .thenReturn(fakeWorkspaceFileValue);
     return env;
   }
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunctionTest.java
index 95e9e88..4e633e4 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunctionTest.java
@@ -17,6 +17,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.FileStateValue;
+import com.google.devtools.build.lib.actions.FileValue;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -131,7 +133,7 @@
   // Dummy harmcrest matcher that match the function name of a skykey
   static class SkyKeyMatchers extends BaseMatcher<SkyKey> {
     private final SkyFunctionName functionName;
-    
+
     public SkyKeyMatchers(SkyFunctionName functionName) {
       this.functionName = functionName;
     }
@@ -142,14 +144,14 @@
       }
       return false;
     }
-    
+
     @Override
     public void describeTo(Description description) {}
   }
 
   private SkyFunction.Environment getEnv() throws InterruptedException {
     SkyFunction.Environment env = Mockito.mock(SkyFunction.Environment.class);
-    Mockito.when(env.getValue(Matchers.argThat(new SkyKeyMatchers(SkyFunctions.FILE))))
+    Mockito.when(env.getValue(Matchers.argThat(new SkyKeyMatchers(FileValue.FILE))))
         .thenReturn(fakeWorkspaceFileValue);
     Mockito.when(env.getValue(Matchers.argThat(new SkyKeyMatchers(SkyFunctions.WORKSPACE_FILE))))
         .then(