diff options
author | Janak Ramakrishnan <janakr@google.com> | 2015-06-17 14:24:34 +0000 |
---|---|---|
committer | John Field <jfield@google.com> | 2015-06-17 15:24:50 +0000 |
commit | b7d3a51a3efefd878e314d3b384083345065e515 (patch) | |
tree | 5c0a289d0ac568d46b26e34c903955ca189d131e /src | |
parent | 09997a0ae07e4222cf1d27290f53e93c6a517d91 (diff) |
Deal properly with IOExceptions when globbing in a single thread.
--
MOS_MIGRATED_REVID=96204334
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/vfs/UnixGlob.java | 81 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/vfs/GlobTest.java | 25 |
2 files changed, 69 insertions, 37 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/UnixGlob.java b/src/main/java/com/google/devtools/build/lib/vfs/UnixGlob.java index 11d88cd324..bde207c13f 100644 --- a/src/main/java/com/google/devtools/build/lib/vfs/UnixGlob.java +++ b/src/main/java/com/google/devtools/build/lib/vfs/UnixGlob.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.vfs; import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Splitter; @@ -73,11 +74,15 @@ public final class UnixGlob { FilesystemCalls syscalls, boolean checkForInterruption, ThreadPoolExecutor threadPool) { - GlobVisitor visitor = (threadPool == null) - ? new GlobVisitor(checkForInterruption) - : new GlobVisitor(threadPool, checkForInterruption); - return visitor.globAsync(base, patterns, excludePatterns, excludeDirectories, dirPred, - syscalls); + Preconditions.checkNotNull(threadPool, "%s %s", base, patterns); + try { + return new GlobVisitor(threadPool, checkForInterruption) + .globAsync(base, patterns, excludePatterns, excludeDirectories, dirPred, syscalls); + } catch (IOException e) { + // We are evaluating asynchronously, so no exceptions should be thrown until the future is + // retrieved. + throw new IllegalStateException(e); + } } /** @@ -459,10 +464,10 @@ public final class UnixGlob { } /** - * Executes the glob asynchronously. + * Executes the glob asynchronously. {@link #setThreadPool} must have been called already with a + * non-null argument. * - * @param checkForInterrupt if the returned future may throw - * InterruptedException. + * @param checkForInterrupt if the returned future may throw InterruptedException. */ public Future<List<Path>> globAsync(boolean checkForInterrupt) { return globAsyncInternal(base, patterns, excludes, excludeDirectories, pathFilter, @@ -610,7 +615,7 @@ public final class UnixGlob { public Future<List<Path>> globAsync(Path base, Collection<String> patterns, Collection<String> excludePatterns, boolean excludeDirectories, - Predicate<Path> dirPred, FilesystemCalls syscalls) { + Predicate<Path> dirPred, FilesystemCalls syscalls) throws IOException { FileStatus baseStat = syscalls.statNullable(base, Symlinks.FOLLOW); if (baseStat == null || patterns.isEmpty()) { @@ -662,35 +667,39 @@ public final class UnixGlob { final List<String[]> excludePatterns, final int excludeIdx, final Collection<Path> results, final Cache<String, Pattern> cache, - final Predicate<Path> dirPred, final FilesystemCalls syscalls) { - enqueue(new Runnable() { - @Override - public void run() { - Profiler.instance().startTask(ProfilerTask.VFS_GLOB, this); - try { - reallyGlob(base, baseIsDir, patternParts, idx, excludeDirectories, - excludePatterns, excludeIdx, results, cache, dirPred, syscalls); - } catch (IOException e) { - throw new IORuntimeException(e); - } catch (InterruptedException e) { - // When we get to this point, the main thread already knows that the - // globbing has been interrupted, so we do not need to report the - // error condition. - } finally { - Profiler.instance().completeTask(ProfilerTask.VFS_GLOB); + final Predicate<Path> dirPred, final FilesystemCalls syscalls) throws IOException { + try { + enqueue(new Runnable() { + @Override + public void run() { + Profiler.instance().startTask(ProfilerTask.VFS_GLOB, this); + try { + reallyGlob(base, baseIsDir, patternParts, idx, excludeDirectories, + excludePatterns, excludeIdx, results, cache, dirPred, syscalls); + } catch (IOException e) { + throw new IORuntimeException(e); + } catch (InterruptedException e) { + // When we get to this point, the main thread already knows that the + // globbing has been interrupted, so we do not need to report the + // error condition. + } finally { + Profiler.instance().completeTask(ProfilerTask.VFS_GLOB); + } } - } - @Override - public String toString() { - return String.format( - "%s glob(include=[%s], exclude=[%s], exclude_directories=%s)", - base.getPathString(), - "\"" + Joiner.on("\", \"").join(patternParts) + "\"", - "\"" + Joiner.on("\", \"").join(excludePatterns) + "\"", - excludeDirectories); - } - }); + @Override + public String toString() { + return String.format( + "%s glob(include=[%s], exclude=[%s], exclude_directories=%s)", + base.getPathString(), + "\"" + Joiner.on("\", \"").join(patternParts) + "\"", + "\"" + Joiner.on("\", \"").join(excludePatterns) + "\"", + excludeDirectories); + } + }); + } catch (IORuntimeException e) { + throw e.getCauseIOException(); + } } diff --git a/src/test/java/com/google/devtools/build/lib/vfs/GlobTest.java b/src/test/java/com/google/devtools/build/lib/vfs/GlobTest.java index 97c6109a48..7b1a7d8e5b 100644 --- a/src/test/java/com/google/devtools/build/lib/vfs/GlobTest.java +++ b/src/test/java/com/google/devtools/build/lib/vfs/GlobTest.java @@ -31,6 +31,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -51,9 +53,18 @@ public class GlobTest { private Path tmpPath; private FileSystem fs; + private Path throwOnReaddir = null; @Before public void setUp() throws Exception { - fs = new InMemoryFileSystem(); + fs = new InMemoryFileSystem() { + @Override + public Collection<Dirent> readdir(Path path, boolean followSymlinks) throws IOException { + if (path.equals(throwOnReaddir)) { + throw new FileNotFoundException(path.getPathString()); + } + return super.readdir(path, followSymlinks); + } + }; tmpPath = fs.getPath("/globtmp"); for (String dir : ImmutableList.of("foo/bar/wiz", "foo/barnacle/wiz", @@ -365,6 +376,18 @@ public class GlobTest { } @Test + public void testIOException() throws Exception { + throwOnReaddir = fs.getPath("/throw_on_readdir"); + throwOnReaddir.createDirectory(); + try { + new UnixGlob.Builder(throwOnReaddir).addPattern("**").glob(); + fail(); + } catch (IOException e) { + // Expected. + } + } + + @Test public void testCheckCanBeInterrupted() throws Exception { final Thread mainThread = Thread.currentThread(); final ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10); |