aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java
diff options
context:
space:
mode:
authorGravatar Han-Wen Nienhuys <hanwen@google.com>2015-02-25 16:45:20 +0100
committerGravatar Han-Wen Nienhuys <hanwen@google.com>2015-02-25 16:45:20 +0100
commitd08b27fa9701fecfdb69e1b0d1ac2459efc2129b (patch)
tree5d50963026239ca5aebfb47ea5b8db7e814e57c8 /src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java
Update from Google.
-- MOE_MIGRATED_REVID=85702957
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java136
1 files changed, 136 insertions, 0 deletions
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
new file mode 100644
index 0000000000..dd4375cfbf
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java
@@ -0,0 +1,136 @@
+// 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.vfs;
+
+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;
+import com.google.devtools.build.lib.unix.FileAccessException;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * This class implements the FileSystem interface using direct calls to the
+ * UNIX filesystem.
+ */
+@ThreadSafe
+abstract class AbstractFileSystem extends FileSystem {
+
+ protected static final String ERR_PERMISSION_DENIED = " (Permission denied)";
+ protected static final Profiler profiler = Profiler.instance();
+
+ @Override
+ protected InputStream getInputStream(Path path) throws FileNotFoundException {
+ // This loop is a workaround for an apparent bug in FileInputStrean.open, which delegates
+ // ultimately to JVM_Open in the Hotspot JVM. This call is not EINTR-safe, so we must do the
+ // retry here.
+ for (;;) {
+ try {
+ return createFileInputStream(path);
+ } catch (FileNotFoundException e) {
+ if (e.getMessage().endsWith("(Interrupted system call)")) {
+ continue;
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns either normal or profiled FileInputStream.
+ */
+ private InputStream createFileInputStream(Path path) throws FileNotFoundException {
+ final String name = path.toString();
+ if (profiler.isActive() && (profiler.isProfiling(ProfilerTask.VFS_READ) ||
+ profiler.isProfiling(ProfilerTask.VFS_OPEN))) {
+ long startTime = Profiler.nanoTimeMaybe();
+ try {
+ // Replace default FileInputStream instance with the custom one that does profiling.
+ return new FileInputStream(name) {
+ @Override public int read(byte b[]) throws IOException {
+ return read(b, 0, b.length);
+ }
+ @Override public int read(byte b[], int off, int len) throws IOException {
+ long startTime = Profiler.nanoTimeMaybe();
+ try {
+ return super.read(b, off, len);
+ } finally {
+ profiler.logSimpleTask(startTime, ProfilerTask.VFS_READ, name);
+ }
+ }
+ };
+ } finally {
+ profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
+ }
+ } else {
+ // Use normal FileInputStream instance if profiler is not enabled.
+ return new FileInputStream(path.toString());
+ }
+ }
+
+ /**
+ * Returns either normal or profiled FileOutputStream. Should be used by subclasses
+ * to create default OutputStream instance.
+ */
+ protected OutputStream createFileOutputStream(Path path, boolean append)
+ throws FileNotFoundException {
+ final String name = path.toString();
+ if (profiler.isActive() && (profiler.isProfiling(ProfilerTask.VFS_WRITE) ||
+ profiler.isProfiling(ProfilerTask.VFS_OPEN))) {
+ long startTime = Profiler.nanoTimeMaybe();
+ try {
+ return new FileOutputStream(name, append) {
+ @Override public void write(byte b[]) throws IOException {
+ write(b, 0, b.length);
+ }
+ @Override public void write(byte b[], int off, int len) throws IOException {
+ long startTime = Profiler.nanoTimeMaybe();
+ try {
+ super.write(b, off, len);
+ } finally {
+ profiler.logSimpleTask(startTime, ProfilerTask.VFS_WRITE, name);
+ }
+ }
+ };
+ } finally {
+ profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
+ }
+ } else {
+ return new FileOutputStream(name, append);
+ }
+ }
+
+ @Override
+ protected OutputStream getOutputStream(Path path, boolean append) throws IOException {
+ synchronized (path) {
+ try {
+ return createFileOutputStream(path, append);
+ } catch (FileNotFoundException e) {
+ // Why does it throw a *FileNotFoundException* if it can't write?
+ // That does not make any sense! And its in a completely different
+ // format than in other situations, no less!
+ if (e.getMessage().equals(path + ERR_PERMISSION_DENIED)) {
+ throw new FileAccessException(e.getMessage());
+ }
+ throw e;
+ }
+ }
+ }
+}