diff options
author | Han-Wen Nienhuys <hanwen@google.com> | 2015-02-25 16:45:20 +0100 |
---|---|---|
committer | Han-Wen Nienhuys <hanwen@google.com> | 2015-02-25 16:45:20 +0100 |
commit | d08b27fa9701fecfdb69e1b0d1ac2459efc2129b (patch) | |
tree | 5d50963026239ca5aebfb47ea5b8db7e814e57c8 /src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java |
Update from Google.
--
MOE_MIGRATED_REVID=85702957
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java new file mode 100644 index 0000000000..7acc38c994 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileArtifactValue.java @@ -0,0 +1,148 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.skyframe; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.cache.DigestUtils; +import com.google.devtools.build.lib.vfs.FileStatus; +import com.google.devtools.build.lib.vfs.Path; + +import java.io.IOException; +import java.util.Arrays; + +import javax.annotation.Nullable; + +/** + * Stores the data of an artifact corresponding to a file. This file may be an ordinary file, in + * which case we would expect to see a digest and size; a directory, in which case we would expect + * to see an mtime; or an empty file, where we would expect to see a size (=0), mtime, and digest + */ +public class FileArtifactValue extends ArtifactValue { + /** Data for Middleman artifacts that did not have data specified. */ + static final FileArtifactValue DEFAULT_MIDDLEMAN = new FileArtifactValue(null, 0, 0); + /** Data that marks that a file is not present on the filesystem. */ + static final FileArtifactValue MISSING_FILE_MARKER = new FileArtifactValue(null, 1, 0); + + @Nullable private final byte[] digest; + private final long mtime; + private final long size; + + private FileArtifactValue(byte[] digest, long size) { + Preconditions.checkState(size >= 0, "size must be non-negative: %s %s", digest, size); + this.digest = Preconditions.checkNotNull(digest, size); + this.size = size; + this.mtime = -1; + } + + // Only used by empty files (non-null digest) and directories (null digest). + private FileArtifactValue(byte[] digest, long mtime, long size) { + Preconditions.checkState(mtime >= 0, "mtime must be non-negative: %s %s", mtime, size); + Preconditions.checkState(size == 0, "size must be zero: %s %s", mtime, size); + this.digest = digest; + this.size = size; + this.mtime = mtime; + } + + static FileArtifactValue create(Artifact artifact) throws IOException { + Path path = artifact.getPath(); + FileStatus stat = path.stat(); + boolean isFile = stat.isFile(); + return create(artifact, isFile, isFile ? stat.getSize() : 0, null); + } + + static FileArtifactValue create(Artifact artifact, FileValue fileValue) throws IOException { + boolean isFile = fileValue.isFile(); + return create(artifact, isFile, isFile ? fileValue.getSize() : 0, + isFile ? fileValue.getDigest() : null); + } + + static FileArtifactValue create(Artifact artifact, boolean isFile, long size, + @Nullable byte[] digest) throws IOException { + if (isFile && digest == null) { + digest = DigestUtils.getDigestOrFail(artifact.getPath(), size); + } + if (!DigestUtils.useFileDigest(artifact, isFile, size)) { + // In this case, we need to store the mtime because the action cache uses mtime to determine + // if this artifact has changed. This is currently true for empty files and directories. We + // do not optimize for this code path (by storing the mtime in a FileValue) because we do not + // like it and may remove this special-casing for empty files in the future. We want this code + // path to go away somehow too for directories (maybe by implementing FileSet + // in Skyframe) + return new FileArtifactValue(digest, artifact.getPath().getLastModifiedTime(), size); + } + Preconditions.checkState(digest != null, artifact); + return new FileArtifactValue(digest, size); + } + + static FileArtifactValue createMiddleman(byte[] digest) { + Preconditions.checkNotNull(digest); + // The Middleman artifact values have size 1 because we want their digests to be used. This hack + // can be removed once empty files are digested. + return new FileArtifactValue(digest, /*size=*/1); + } + + @Nullable + byte[] getDigest() { + return digest; + } + + /** Gets the size of the file. Directories have size 0. */ + long getSize() { + return size; + } + + /** + * Gets last modified time of file. Should only be called if {@link DigestUtils#useFileDigest} was + * false for this artifact -- namely, either it is a directory or an empty file. Note that since + * we store directory sizes as 0, all files for which this method can be called have size 0. + */ + long getModifiedTime() { + Preconditions.checkState(size == 0, "%s %s %s", digest, mtime, size); + return mtime; + } + + @Override + public int hashCode() { + // Hash digest by content, not reference. Note that digest is the only array in this array. + return Arrays.deepHashCode(new Object[] {size, mtime, digest}); + } + + /** + * Two FileArtifactValues will only compare equal if they have the same content. This differs + * from the {@code Metadata#equivalence} method, which allows for comparison using mtime if + * one object does not have a digest available. + */ + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof FileArtifactValue)) { + return false; + } + FileArtifactValue that = (FileArtifactValue) other; + return this.mtime == that.mtime && this.size == that.size + && Arrays.equals(this.digest, that.digest); + } + + @Override + public String toString() { + return Objects.toStringHelper(FileArtifactValue.class) + .add("digest", digest) + .add("mtime", mtime) + .add("size", size).toString(); + } +} |