Automated rollback of commit 8181f0abe6591bc14957e6a941a6556fb040ca9f.
*** Reason for rollback ***
b/198749645
*** Original change description ***
Add a new `FileSystem` method to get a `SeekableByteChannel` for writing files.
Add `FileSystem::createSeekableChannel` which allows us to create a `SeekableByteChannel` for file writes. The channel is opened in truncated mode, meaning that it is not suitable for reading existing files.
PiperOrigin-RevId: 394690266
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java
index 1ff1435..8a4e53d 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java
@@ -14,13 +14,8 @@
//
package com.google.devtools.build.lib.vfs;
-import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.READ;
-import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
-import static java.nio.file.StandardOpenOption.WRITE;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.profiler.Profiler;
import com.google.devtools.build.lib.profiler.ProfilerTask;
@@ -32,11 +27,8 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
-import java.nio.file.OpenOption;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
+import java.util.EnumSet;
/** This class implements the FileSystem interface using direct calls to the UNIX filesystem. */
@ThreadSafe
@@ -91,42 +83,21 @@
}
}
- private static final ImmutableSet<StandardOpenOption> READABLE_BYTE_CHANNEL_OPEN_OPTIONS =
- Sets.immutableEnumSet(READ);
- private static final ImmutableSet<ProfilerTask> READABLE_BYTE_CHANNEL_PROFILER_TASKS =
- Sets.immutableEnumSet(ProfilerTask.VFS_OPEN, ProfilerTask.VFS_READ);
- private static final ImmutableSet<StandardOpenOption> READ_WRITE_BYTE_CHANNEL_OPEN_OPTIONS =
- Sets.immutableEnumSet(READ, WRITE, CREATE, TRUNCATE_EXISTING);
- private static final ImmutableSet<ProfilerTask> READ_WRITE_BYTE_CHANNEL_PROFILER_TASKS =
- Sets.immutableEnumSet(ProfilerTask.VFS_OPEN, ProfilerTask.VFS_READ, ProfilerTask.VFS_WRITE);
-
@Override
protected ReadableByteChannel createReadableByteChannel(PathFragment path) throws IOException {
- return createSeekableByteChannelInternal(
- path, READABLE_BYTE_CHANNEL_OPEN_OPTIONS, READABLE_BYTE_CHANNEL_PROFILER_TASKS);
- }
-
- @Override
- protected SeekableByteChannel createReadWriteByteChannel(PathFragment path) throws IOException {
- return createSeekableByteChannelInternal(
- path, READ_WRITE_BYTE_CHANNEL_OPEN_OPTIONS, READ_WRITE_BYTE_CHANNEL_PROFILER_TASKS);
- }
-
- private static SeekableByteChannel createSeekableByteChannelInternal(
- PathFragment path,
- ImmutableSet<? extends OpenOption> options,
- ImmutableSet<ProfilerTask> profilerTasks)
- throws IOException {
- String name = path.getPathString();
- if (!profiler.isActive() || profilerTasks.stream().noneMatch(profiler::isProfiling)) {
- return Files.newByteChannel(Paths.get(name), options);
- }
- long startTime = Profiler.nanoTimeMaybe();
- try {
- // Currently, we do not proxy SeekableByteChannel for profiling.
- return Files.newByteChannel(Paths.get(name), options);
- } finally {
- profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
+ final String name = path.toString();
+ if (profiler.isActive()
+ && (profiler.isProfiling(ProfilerTask.VFS_READ)
+ || profiler.isProfiling(ProfilerTask.VFS_OPEN))) {
+ long startTime = Profiler.nanoTimeMaybe();
+ try {
+ // Currently, we do not proxy ReadableByteChannel for profiling.
+ return Files.newByteChannel(java.nio.file.Paths.get(name), EnumSet.of(READ));
+ } finally {
+ profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
+ }
+ } else {
+ return Files.newByteChannel(java.nio.file.Paths.get(name));
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/BUILD b/src/main/java/com/google/devtools/build/lib/vfs/BUILD
index 2f1c648..bcd1791 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/vfs/BUILD
@@ -59,7 +59,6 @@
"//third_party:caffeine",
"//third_party:guava",
"//third_party:jsr305",
- "//third_party/protobuf:protobuf_java",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
index 67a225b..283e87b 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
@@ -28,7 +28,6 @@
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.SeekableByteChannel;
import java.nio.file.FileAlreadyExistsException;
import java.util.Collection;
import java.util.Iterator;
@@ -721,16 +720,6 @@
}
/**
- * Returns a {@link SeekableByteChannel} for writing to a file at provided path.
- *
- * <p>Truncates the target file, therefore it cannot be used to read already existing files.
- * Please use {@link #createReadableByteChannel} to get a {@linkplain ReadableByteChannel channel}
- * for reads instead.
- */
- protected abstract SeekableByteChannel createReadWriteByteChannel(PathFragment path)
- throws IOException;
-
- /**
* Creates an OutputStream accessing the file denoted by path.
*
* @throws IOException if there was an error opening the file for writing
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/Path.java b/src/main/java/com/google/devtools/build/lib/vfs/Path.java
index bfc4161..71d21c6 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/Path.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/Path.java
@@ -32,7 +32,6 @@
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.SeekableByteChannel;
import java.util.ArrayList;
import java.util.Collection;
import javax.annotation.Nullable;
@@ -791,21 +790,10 @@
}
/**
- * Opens the file denoted by this path, following symbolic links, for reading and writing and
- * returns a file channel for it.
- *
- * <p>Truncates the file, therefore it cannot be used to read already existing files. Please use
- * {@link #createReadableByteChannel} to get a {@linkplain ReadableByteChannel channel} for reads
- * instead.
- */
- public SeekableByteChannel createReadWriteByteChannel() throws IOException {
- return fileSystem.createReadWriteByteChannel(asFragment());
- }
-
- /**
* Returns a java.io.File representation of this path.
*
- * <p>Caveat: the result may be useless if this path's getFileSystem() is not the UNIX filesystem.
+ * <p>Caveat: the result may be useless if this path's getFileSystem() is not
+ * the UNIX filesystem.
*/
public File getPathFile() {
return new File(getPathString());
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/PathTransformingDelegateFileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/PathTransformingDelegateFileSystem.java
index 063ecc6..3070239 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/PathTransformingDelegateFileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/PathTransformingDelegateFileSystem.java
@@ -19,7 +19,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.SeekableByteChannel;
import java.util.Collection;
/**
@@ -179,11 +178,6 @@
}
@Override
- protected SeekableByteChannel createReadWriteByteChannel(PathFragment path) throws IOException {
- return delegateFs.createReadWriteByteChannel(toDelegatePath(path));
- }
-
- @Override
protected OutputStream getOutputStream(PathFragment path, boolean append) throws IOException {
return delegateFs.getOutputStream(toDelegatePath(path), append);
}
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs/InMemoryFileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs/InMemoryFileSystem.java
index 39eb14f..097f7fa 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs/InMemoryFileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs/InMemoryFileSystem.java
@@ -35,7 +35,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.SeekableByteChannel;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
@@ -612,12 +611,6 @@
}
@Override
- protected synchronized SeekableByteChannel createReadWriteByteChannel(PathFragment path) {
- // It's feasible to implement, but so far it is not needed.
- throw new UnsupportedOperationException("Not implemented");
- }
-
- @Override
protected synchronized byte[] getFastDigest(PathFragment path) throws IOException {
return statFile(path).getFastDigest();
}
diff --git a/src/test/java/com/google/devtools/build/lib/vfs/BUILD b/src/test/java/com/google/devtools/build/lib/vfs/BUILD
index 662b976..49defcd 100644
--- a/src/test/java/com/google/devtools/build/lib/vfs/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/vfs/BUILD
@@ -66,8 +66,10 @@
"//src/test/java/com/google/devtools/build/lib/testutil:TestThread",
"//src/test/java/com/google/devtools/build/lib/testutil:TestUtils",
"//src/test/java/com/google/devtools/build/lib/vfs/util",
+ "//third_party:caffeine",
"//third_party:guava",
"//third_party:guava-testlib",
+ "//third_party:jsr305",
"//third_party:junit4",
"//third_party:mockito",
"//third_party:truth",
@@ -88,7 +90,6 @@
"//third_party:guava",
"//third_party:junit4",
"//third_party:truth",
- "@com_google_testparameterinjector//:testparameterinjector",
],
)
@@ -146,6 +147,5 @@
"//third_party:guava",
"//third_party:junit4",
"//third_party:truth",
- "@com_google_testparameterinjector//:testparameterinjector",
],
)
diff --git a/src/test/java/com/google/devtools/build/lib/vfs/FileSystemTest.java b/src/test/java/com/google/devtools/build/lib/vfs/FileSystemTest.java
index 09fc304..b4f6f60 100644
--- a/src/test/java/com/google/devtools/build/lib/vfs/FileSystemTest.java
+++ b/src/test/java/com/google/devtools/build/lib/vfs/FileSystemTest.java
@@ -14,9 +14,7 @@
//
package com.google.devtools.build.lib.vfs;
-import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.truth.Truth.assertThat;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
@@ -28,9 +26,6 @@
import com.google.devtools.build.lib.unix.FileStatus;
import com.google.devtools.build.lib.unix.NativePosixFiles;
import com.google.devtools.build.lib.util.Fingerprint;
-import com.google.testing.junit.testparameterinjector.TestParameter;
-import com.google.testing.junit.testparameterinjector.TestParameter.TestParameterValuesProvider;
-import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -38,10 +33,9 @@
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.SeekableByteChannel;
-import java.nio.channels.WritableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileAlreadyExistsException;
+import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
@@ -50,13 +44,17 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
/**
* This class handles the generic tests that any filesystem must pass.
*
- * <p>Each filesystem-test should inherit from this class, thereby obtaining all the tests.
+ * <p>Each filesystem-test should inherit from this class, thereby obtaining
+ * all the tests.
*/
-@RunWith(TestParameterInjector.class)
+@RunWith(Parameterized.class)
public abstract class FileSystemTest {
private long savedTime;
@@ -71,16 +69,19 @@
protected Path xNonEmptyDirectoryFoo;
protected Path xEmptyDirectory;
- @TestParameter(valuesProvider = DigestHashFunctionsProvider.class)
- public DigestHashFunction digestHashFunction;
-
- private static final class DigestHashFunctionsProvider implements TestParameterValuesProvider {
- @Override
- public ImmutableList<?> provideValues() {
- return DigestHashFunction.getPossibleHashFunctions().asList();
- }
+ @Parameters(name = "{index}: digestHashFunction={0}")
+ public static Collection<DigestHashFunction[]> hashFunctions() {
+ // TODO(b/112537387): Remove the array-ification and return Collection<DigestHashFunction>. This
+ // is possible in Junit4.12, but 4.11 requires the array. Bazel 0.18 will have Junit4.12, so
+ // this can change then.
+ return DigestHashFunction.getPossibleHashFunctions()
+ .stream()
+ .map(dhf -> new DigestHashFunction[] {dhf})
+ .collect(ImmutableList.toImmutableList());
}
+ @Parameter public DigestHashFunction digestHashFunction;
+
@Before
public final void createDirectories() throws Exception {
testFS = getFreshFileSystem(digestHashFunction);
@@ -1320,74 +1321,6 @@
}
}
- @Test
- public void testCreateReadWriteByteChannelWrite(@TestParameter boolean overwrite)
- throws Exception {
- String text = "hello";
- Path file = overwrite ? xFile : xNothing;
- try (SeekableByteChannel channel = file.createReadWriteByteChannel()) {
- writeToChannelAsLatin1(channel, text);
- assertThat(channel.position()).isEqualTo(text.length());
- }
-
- assertThat(FileSystemUtils.readContent(file, ISO_8859_1)).isEqualTo("hello");
- }
-
- @Test
- public void testCreateReadWriteByteChannelWriteAfterSeek() throws Exception {
- try (SeekableByteChannel channel = xNothing.createReadWriteByteChannel()) {
- writeToChannelAsLatin1(channel, "01234567890");
- channel.position(5);
- writeToChannelAsLatin1(channel, "hello!");
- assertThat(channel.position()).isEqualTo(5 + "hello!".length());
- }
-
- assertThat(FileSystemUtils.readContent(xNothing, ISO_8859_1)).isEqualTo("01234hello!");
- }
-
- @Test
- public void testCreateReadWriteByteChannelRead(@TestParameter({"0", "5", "12"}) int seekPosition)
- throws Exception {
- String text = "hello there!";
- try (SeekableByteChannel channel = xNothing.createReadWriteByteChannel()) {
- writeToChannelAsLatin1(channel, text);
- channel.position(seekPosition);
-
- String read = readAllAsString(channel, text.length() - seekPosition);
- assertThat(channel.position()).isEqualTo(text.length());
- assertThat(read).isEqualTo(text.substring(seekPosition));
- }
- }
-
- private static void writeToChannelAsLatin1(WritableByteChannel channel, String text)
- throws IOException {
- byte[] bytes = text.getBytes(ISO_8859_1);
- ByteBuffer buffer = ByteBuffer.wrap(bytes);
- int toWrite = bytes.length;
- while (toWrite > 0) {
- toWrite -= channel.write(buffer);
- }
- assertThat(toWrite).isEqualTo(0);
- assertThat(buffer.remaining()).isEqualTo(0);
- }
-
- private static String readAllAsString(ReadableByteChannel channel, int expectedSize)
- throws IOException {
- checkArgument(expectedSize >= 0, "negative expected size: %s", expectedSize);
- // +1 to make sure we can observe EOF -- Channel::read will always return 0 for a full buffer.
- ByteBuffer buffer = ByteBuffer.allocate(expectedSize + 1);
- int totalRead = 0;
- for (; ; ) {
- int read = channel.read(buffer);
- if (read == -1) {
- assertThat(totalRead).isEqualTo(expectedSize);
- return new String(buffer.array(), 0, expectedSize, ISO_8859_1);
- }
- totalRead += read;
- assertThat(buffer.position()).isEqualTo(totalRead);
- }
- }
-
private static int readFromChannel(ReadableByteChannel channel, ByteBuffer buffer, int expected)
throws IOException {
int numRead = 0;
diff --git a/src/test/java/com/google/devtools/build/lib/vfs/inmemoryfs/InMemoryFileSystemTest.java b/src/test/java/com/google/devtools/build/lib/vfs/inmemoryfs/InMemoryFileSystemTest.java
index 827e3f2..e1654a0 100644
--- a/src/test/java/com/google/devtools/build/lib/vfs/inmemoryfs/InMemoryFileSystemTest.java
+++ b/src/test/java/com/google/devtools/build/lib/vfs/inmemoryfs/InMemoryFileSystemTest.java
@@ -26,7 +26,6 @@
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.SymlinkAwareFileSystemTest;
-import com.google.testing.junit.testparameterinjector.TestParameter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -65,8 +64,8 @@
}
/**
- * Tests concurrent creation of a substantial tree hierarchy including files, directories,
- * symlinks, file contents, and permissions.
+ * Tests concurrent creation of a substantial tree hierarchy including
+ * files, directories, symlinks, file contents, and permissions.
*/
@Test
public void testConcurrentTreeConstruction() throws Exception {
@@ -411,19 +410,4 @@
assertThat(symlink.getxattr("some.xattr")).isNull();
}
-
- // createSeekableByteChannel is not supported by InMemoryFileSystem.
- @Test
- @Override
- public void testCreateReadWriteByteChannelWrite(@TestParameter boolean overwrite) {}
-
- // createSeekableByteChannel is not supported by InMemoryFileSystem.
- @Test
- @Override
- public void testCreateReadWriteByteChannelWriteAfterSeek() {}
-
- // createSeekableByteChannel is not supported by InMemoryFileSystem.
- @Test
- @Override
- public void testCreateReadWriteByteChannelRead(@TestParameter({"0"}) int seekPosition) {}
}