diff options
5 files changed, 133 insertions, 26 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java index 8dca37c391..2b845edc38 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java @@ -13,21 +13,23 @@ // limitations under the License. package com.google.devtools.build.lib.skyframe; +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; import java.util.Objects; /** - * In case we can't get a fast digest from the filesystem, we store this metadata as a proxy to - * the file contents. Currently it is a pair of a relevant timestamp and a "node id". On Linux the - * former is the ctime and the latter is the inode number. We might want to add the device number - * in the future. + * In case we can't get a fast digest from the filesystem, we store this metadata as a proxy to the + * file contents. Currently it is a pair of a relevant timestamp and a "node id". On Linux the + * former is the ctime and the latter is the inode number. We might want to add the device number in + * the future. * * <p>For a Linux example of why mtime alone is insufficient, note that 'mv' preserves timestamps. * 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; diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java index 56988b8adb..f92e561ffa 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java @@ -58,8 +58,11 @@ import javax.annotation.Nullable; @VisibleForTesting public abstract class FileStateValue implements SkyValue { + @AutoCodec public static final DirectoryFileStateValue DIRECTORY_FILE_STATE_NODE = new DirectoryFileStateValue(); + + @AutoCodec public static final NonexistentFileStateValue NONEXISTENT_FILE_STATE_NODE = new NonexistentFileStateValue(); @@ -151,10 +154,11 @@ public abstract class FileStateValue implements SkyValue { * * <p>A union of (digest, mtime). We use digests only if a fast digest lookup is available from * the filesystem. If not, we fall back to mtime-based digests. This avoids the case where Blaze - * must read all files involved in the build in order to check for modifications in the case - * where fast digest lookups are not available. + * must read all files involved in the build in order to check for modifications in the case where + * fast digest lookups are not available. */ @ThreadSafe + @AutoCodec public static final class RegularFileStateValue extends FileStateValue { private final long size; @Nullable private final byte[] digest; @@ -270,6 +274,7 @@ public abstract class FileStateValue implements SkyValue { } /** Implementation of {@link FileStateValue} for special files that exist. */ + @AutoCodec public static final class SpecialFileStateValue extends FileStateValue { private final FileContentsProxy contentsProxy; @@ -330,7 +335,8 @@ public abstract class FileStateValue implements SkyValue { } /** Implementation of {@link FileStateValue} for directories that exist. */ - public static final class DirectoryFileStateValue extends FileStateValue { + @AutoCodec.VisibleForSerialization + static final class DirectoryFileStateValue extends FileStateValue { private DirectoryFileStateValue() { } @@ -358,6 +364,7 @@ public abstract class FileStateValue implements SkyValue { } /** Implementation of {@link FileStateValue} for symlinks. */ + @AutoCodec public static final class SymlinkFileStateValue extends FileStateValue { private final PathFragment symlinkTarget; @@ -397,7 +404,8 @@ public abstract class FileStateValue implements SkyValue { } /** Implementation of {@link FileStateValue} for nonexistent files. */ - public static final class NonexistentFileStateValue extends FileStateValue { + @AutoCodec.VisibleForSerialization + static final class NonexistentFileStateValue extends FileStateValue { private NonexistentFileStateValue() { } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java index a0fe84db92..46e75cef19 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java @@ -13,6 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.skyframe; +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; @@ -168,14 +169,16 @@ public abstract class FileValue implements SkyValue { * requested path. For example, this is the case for the path "foo/bar/baz" if neither 'foo' nor * 'foo/bar' nor 'foo/bar/baz' are symlinks. */ + @VisibleForTesting + @AutoCodec public static final class RegularFileValue extends FileValue { private final RootedPath rootedPath; private final FileStateValue fileStateValue; - public RegularFileValue(RootedPath rootedPath, FileStateValue fileState) { + public RegularFileValue(RootedPath rootedPath, FileStateValue fileStateValue) { this.rootedPath = Preconditions.checkNotNull(rootedPath); - this.fileStateValue = Preconditions.checkNotNull(fileState); + this.fileStateValue = Preconditions.checkNotNull(fileStateValue); } @Override @@ -216,13 +219,15 @@ public abstract class FileValue implements SkyValue { * requested path. For example, this is the case for the path "foo/bar/baz" if at least one of * 'foo', 'foo/bar', or 'foo/bar/baz' is a symlink. */ - public static class DifferentRealPathFileValue extends FileValue { + @AutoCodec.VisibleForSerialization + @AutoCodec + static class DifferentRealPathFileValue extends FileValue { protected final RootedPath realRootedPath; protected final FileStateValue realFileStateValue; - public DifferentRealPathFileValue(RootedPath realRootedPath, - FileStateValue realFileStateValue) { + @AutoCodec.VisibleForSerialization + DifferentRealPathFileValue(RootedPath realRootedPath, FileStateValue realFileStateValue) { this.realRootedPath = Preconditions.checkNotNull(realRootedPath); this.realFileStateValue = Preconditions.checkNotNull(realFileStateValue); } @@ -262,13 +267,16 @@ public abstract class FileValue implements SkyValue { } /** Implementation of {@link FileValue} for files that are symlinks. */ - public static final class SymlinkFileValue extends DifferentRealPathFileValue { - private final PathFragment linkValue; - - public SymlinkFileValue(RootedPath realRootedPath, FileStateValue realFileState, - PathFragment linkTarget) { - super(realRootedPath, realFileState); - this.linkValue = linkTarget; + @VisibleForTesting + @AutoCodec + static final class SymlinkFileValue extends DifferentRealPathFileValue { + private final PathFragment linkTarget; + + @VisibleForTesting + SymlinkFileValue( + RootedPath realRootedPath, FileStateValue realFileStateValue, PathFragment linkTarget) { + super(realRootedPath, realFileStateValue); + this.linkTarget = linkTarget; } @Override @@ -278,7 +286,7 @@ public abstract class FileValue implements SkyValue { @Override public PathFragment getUnresolvedLinkTarget() { - return linkValue; + return linkTarget; } @Override @@ -292,19 +300,19 @@ public abstract class FileValue implements SkyValue { SymlinkFileValue other = (SymlinkFileValue) obj; return realRootedPath.equals(other.realRootedPath) && realFileStateValue.equals(other.realFileStateValue) - && linkValue.equals(other.linkValue); + && linkTarget.equals(other.linkTarget); } @Override public int hashCode() { - return Objects.hash( - realRootedPath, realFileStateValue, linkValue, Boolean.TRUE); + return Objects.hash(realRootedPath, realFileStateValue, linkTarget, Boolean.TRUE); } @Override public String toString() { - return String.format("symlink (real_path=%s, real_state=%s, link_value=%s)", - realRootedPath, realFileStateValue, linkValue); + return String.format( + "symlink (real_path=%s, real_state=%s, link_value=%s)", + realRootedPath, realFileStateValue, linkTarget); } } } 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 new file mode 100644 index 0000000000..36f8d248b7 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileStateValueTest.java @@ -0,0 +1,45 @@ +// 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 com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester; +import com.google.devtools.build.lib.vfs.PathFragment; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link FileStateValue}. */ +@RunWith(JUnit4.class) +public class FileStateValueTest { + @Test + public void testCodec() throws Exception { + new SerializationTester( + new FileStateValue.RegularFileStateValue( + /*size=*/ 1, /*digest=*/ new byte[] {1, 2, 3}, /*contentsProxy=*/ null), + new FileStateValue.RegularFileStateValue( + /*size=*/ 1, /*digest=*/ new byte[0], /*contentsProxy=*/ null), + new FileStateValue.RegularFileStateValue( + /*size=*/ 1, + /*digest=*/ null, + new FileContentsProxy(/* ctime= */ 2, /* nodeId= */ 42)), + new FileStateValue.SpecialFileStateValue( + new FileContentsProxy(/* ctime= */ 4, /* nodeId= */ 84)), + FileStateValue.DIRECTORY_FILE_STATE_NODE, + new FileStateValue.SymlinkFileStateValue(PathFragment.create("somewhere/elses")), + FileStateValue.NONEXISTENT_FILE_STATE_NODE) + .runTests(); + } + +} 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 new file mode 100644 index 0000000000..c6d0a34d74 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileValueTest.java @@ -0,0 +1,44 @@ +// 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 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; +import com.google.devtools.build.lib.vfs.PathFragment; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link FileValue}. */ +@RunWith(JUnit4.class) +public class FileValueTest { + @Test + public void testCodec() throws Exception { + new SerializationTester( + // Assume we have adequate coverage for FileStateValue serialization. + new FileValue.RegularFileValue( + FsUtils.TEST_ROOT, FileStateValue.NONEXISTENT_FILE_STATE_NODE), + new FileValue.DifferentRealPathFileValue( + FsUtils.TEST_ROOT, FileStateValue.DIRECTORY_FILE_STATE_NODE), + new FileValue.SymlinkFileValue( + FsUtils.TEST_ROOT, + new FileStateValue.RegularFileStateValue( + /*size=*/ 100, /*digest=*/ new byte[] {1, 2, 3, 4, 5}, /*contentsProxy=*/ null), + PathFragment.create("somewhere/else"))) + .addDependency(FileSystem.class, FsUtils.TEST_FILESYSTEM) + .runTests(); + } +} |