diff options
author | 2017-12-19 11:54:08 -0800 | |
---|---|---|
committer | 2017-12-19 11:55:35 -0800 | |
commit | 18291e570fc8823f13d1afd355cf57c0b68f8426 (patch) | |
tree | ad23c9a379d858ab60321e6f394acdad3172a7f6 /src/test/java/com | |
parent | 246ee5601c28e99385a2a722b57c1977d5ef1aa8 (diff) |
Add regression test for JavaIoFileSystem#createDirectory.
PiperOrigin-RevId: 179584358
Diffstat (limited to 'src/test/java/com')
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java | 74 |
1 files changed, 68 insertions, 6 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java b/src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java index 80c1981fcd..056b5f0f1a 100644 --- a/src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java +++ b/src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java @@ -15,11 +15,24 @@ package com.google.devtools.build.lib.vfs; import static com.google.common.truth.Truth.assertThat; +import com.google.common.collect.Iterables; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; import com.google.devtools.build.lib.testutil.ManualClock; +import com.google.devtools.build.lib.testutil.TestUtils; import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; +import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -66,15 +79,64 @@ public class JavaIoFileSystemTest extends SymlinkAwareFileSystemTest { @Override protected boolean isHardLinked(Path a, Path b) throws IOException { return Files.readAttributes( - java.nio.file.Paths.get(a.toString()), - BasicFileAttributes.class, - LinkOption.NOFOLLOW_LINKS) + Paths.get(a.toString()), BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS) .fileKey() .equals( Files.readAttributes( - java.nio.file.Paths.get(b.toString()), - BasicFileAttributes.class, - LinkOption.NOFOLLOW_LINKS) + Paths.get(b.toString()), BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS) .fileKey()); } + + /** + * This test has a large number of threads racing to create the same subdirectories. + * + * <p>We create N number of distinct directory trees, eg. the tree "0-0/0-1/0-2/0-3/0-4" followed + * by the tree "1-0/1-1/1-2/1-3/1-4" etc. If there is race we should quickly get a deadlock. + * + * <p>A timeout of this test is likely because of a deadlock. + */ + @Test + public void testCreateDirectoriesThreadSafety() throws Exception { + int threadCount = 200; + int directoryCreationCount = 500; // We create this many sets of directories + int subDirectoryCount = 5; // Each directory tree is this deep + ListeningExecutorService executor = + MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(threadCount)); + List<ListenableFuture<IOException>> futures = new ArrayList<>(); + for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex) { + futures.add( + executor.submit( + () -> { + try { + for (int loopi = 0; loopi < directoryCreationCount; ++loopi) { + List<Path> subDirs = + getSubDirectories(xEmptyDirectory, loopi, subDirectoryCount); + Path lastDir = Iterables.getLast(subDirs); + FileSystemUtils.createDirectoryAndParents(lastDir); + } + } catch (IOException e) { + return e; + } + return null; + })); + } + ListenableFuture<List<IOException>> all = Futures.allAsList(futures); + // If the test times out here then there's likely to be a deadlock + List<IOException> exceptions = + all.get(TestUtils.WAIT_TIMEOUT_MILLISECONDS, TimeUnit.MILLISECONDS); + Optional<IOException> error = exceptions.stream().filter(Objects::nonNull).findFirst(); + if (error.isPresent()) { + throw error.get(); + } + } + + private static List<Path> getSubDirectories(Path base, int loopi, int subDirectoryCount) { + Path path = base; + List<Path> subDirs = new ArrayList<>(); + for (int subDirIndex = 0; subDirIndex < subDirectoryCount; ++subDirIndex) { + path = path.getChild(String.format("%d-%d", loopi, subDirIndex)); + subDirs.add(path); + } + return subDirs; + } } |