blob: 73a2e735f1bfd5af9b302f0170a2b912adff69a4 [file] [log] [blame]
Googler4785a952019-10-22 04:54:34 -07001// Copyright 2019 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Googler4785a952019-10-22 04:54:34 -070014//
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010015package com.google.devtools.build.lib.vfs;
16
ichern03be73e2019-10-22 10:16:44 -070017import static java.nio.file.StandardOpenOption.READ;
18
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
20import com.google.devtools.build.lib.profiler.Profiler;
21import com.google.devtools.build.lib.profiler.ProfilerTask;
ccalvarinc2f18962018-08-22 15:08:40 -070022import com.google.devtools.build.lib.vfs.DigestHashFunction.DefaultHashFunctionNotSetException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010023import java.io.FileInputStream;
24import java.io.FileNotFoundException;
25import java.io.FileOutputStream;
John Millikineae93f62019-11-11 09:01:04 -080026import java.io.FilterInputStream;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import java.io.IOException;
28import java.io.InputStream;
29import java.io.OutputStream;
Googler4785a952019-10-22 04:54:34 -070030import java.nio.channels.ReadableByteChannel;
31import java.nio.file.Files;
ichern03be73e2019-10-22 10:16:44 -070032import java.util.EnumSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000034/** This class implements the FileSystem interface using direct calls to the UNIX filesystem. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010035@ThreadSafe
shahanb1dd4e32018-05-09 08:23:31 -070036public abstract class AbstractFileSystem extends FileSystem {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010037
38 protected static final String ERR_PERMISSION_DENIED = " (Permission denied)";
39 protected static final Profiler profiler = Profiler.instance();
40
ccalvarinc2f18962018-08-22 15:08:40 -070041 public AbstractFileSystem() throws DefaultHashFunctionNotSetException {}
ccalvarinc9efd062018-07-27 12:46:46 -070042
ccalvarinbda12a12018-06-21 18:57:26 -070043 public AbstractFileSystem(DigestHashFunction digestFunction) {
buchgr559a07d2017-11-30 11:09:35 -080044 super(digestFunction);
45 }
46
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010047 @Override
aehligc801c392017-12-19 07:12:25 -080048 protected InputStream getInputStream(Path path) throws IOException {
Googler89100872016-07-26 15:52:48 +000049 // This loop is a workaround for an apparent bug in FileInputStream.open, which delegates
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010050 // ultimately to JVM_Open in the Hotspot JVM. This call is not EINTR-safe, so we must do the
51 // retry here.
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000052 for (; ; ) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010053 try {
John Millikineae93f62019-11-11 09:01:04 -080054 return createMaybeProfiledInputStream(path);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010055 } catch (FileNotFoundException e) {
56 if (e.getMessage().endsWith("(Interrupted system call)")) {
57 continue;
58 } else {
59 throw e;
60 }
61 }
62 }
63 }
64
John Millikineae93f62019-11-11 09:01:04 -080065 /** Allows the mapping of Path to InputStream to be overridden in subclasses. */
66 protected InputStream createFileInputStream(Path path) throws IOException {
67 return new FileInputStream(path.toString());
68 }
69
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000070 /** Returns either normal or profiled FileInputStream. */
John Millikineae93f62019-11-11 09:01:04 -080071 private InputStream createMaybeProfiledInputStream(Path path) throws IOException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010072 final String name = path.toString();
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000073 if (profiler.isActive()
74 && (profiler.isProfiling(ProfilerTask.VFS_READ)
75 || profiler.isProfiling(ProfilerTask.VFS_OPEN))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076 long startTime = Profiler.nanoTimeMaybe();
77 try {
78 // Replace default FileInputStream instance with the custom one that does profiling.
John Millikineae93f62019-11-11 09:01:04 -080079 return new ProfiledInputStream(createFileInputStream(path), name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010080 } finally {
81 profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
82 }
83 } else {
84 // Use normal FileInputStream instance if profiler is not enabled.
John Millikineae93f62019-11-11 09:01:04 -080085 return createFileInputStream(path);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010086 }
87 }
88
Googler4785a952019-10-22 04:54:34 -070089 @Override
ichern03be73e2019-10-22 10:16:44 -070090 protected ReadableByteChannel createReadableByteChannel(Path path) throws IOException {
Googler4785a952019-10-22 04:54:34 -070091 final String name = path.toString();
92 if (profiler.isActive()
93 && (profiler.isProfiling(ProfilerTask.VFS_READ)
94 || profiler.isProfiling(ProfilerTask.VFS_OPEN))) {
95 long startTime = Profiler.nanoTimeMaybe();
96 try {
97 // Currently, we do not proxy ReadableByteChannel for profiling.
ichern03be73e2019-10-22 10:16:44 -070098 return Files.newByteChannel(java.nio.file.Paths.get(name), EnumSet.of(READ));
Googler4785a952019-10-22 04:54:34 -070099 } finally {
100 profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
101 }
102 } else {
103 return Files.newByteChannel(java.nio.file.Paths.get(name));
104 }
105 }
106
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100107 /**
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000108 * Returns either normal or profiled FileOutputStream. Should be used by subclasses to create
109 * default OutputStream instance.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100110 */
Yun Pengd2920e32018-11-27 02:07:55 -0800111 protected OutputStream createFileOutputStream(Path path, boolean append)
112 throws FileNotFoundException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100113 final String name = path.toString();
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000114 if (profiler.isActive()
115 && (profiler.isProfiling(ProfilerTask.VFS_WRITE)
116 || profiler.isProfiling(ProfilerTask.VFS_OPEN))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100117 long startTime = Profiler.nanoTimeMaybe();
118 try {
Yun Pengd2920e32018-11-27 02:07:55 -0800119 return new ProfiledFileOutputStream(name, append);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100120 } finally {
121 profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
122 }
123 } else {
Yun Pengd2920e32018-11-27 02:07:55 -0800124 return new FileOutputStream(name, append);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100125 }
126 }
127
128 @Override
aehligc801c392017-12-19 07:12:25 -0800129 protected OutputStream getOutputStream(Path path, boolean append) throws IOException {
tomlu22c2f9a2018-01-09 13:52:13 -0800130 try {
131 return createFileOutputStream(path, append);
132 } catch (FileNotFoundException e) {
133 // Why does it throw a *FileNotFoundException* if it can't write?
134 // That does not make any sense! And its in a completely different
135 // format than in other situations, no less!
136 if (e.getMessage().equals(path + ERR_PERMISSION_DENIED)) {
137 throw new FileAccessException(e.getMessage());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100138 }
tomlu22c2f9a2018-01-09 13:52:13 -0800139 throw e;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100140 }
141 }
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000142
John Millikineae93f62019-11-11 09:01:04 -0800143 private static final class ProfiledInputStream extends FilterInputStream {
144 private final InputStream impl;
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000145 private final String name;
146
John Millikineae93f62019-11-11 09:01:04 -0800147 public ProfiledInputStream(InputStream impl, String name) {
148 super(impl);
149 this.impl = impl;
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000150 this.name = name;
151 }
152
153 @Override
154 public int read() throws IOException {
155 long startTime = Profiler.nanoTimeMaybe();
156 try {
John Millikineae93f62019-11-11 09:01:04 -0800157 return impl.read();
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000158 } finally {
159 profiler.logSimpleTask(startTime, ProfilerTask.VFS_READ, name);
160 }
161 }
162
163 @Override
164 public int read(byte[] b) throws IOException {
165 return read(b, 0, b.length);
166 }
167
168 @Override
169 public int read(byte[] b, int off, int len) throws IOException {
170 long startTime = Profiler.nanoTimeMaybe();
171 try {
John Millikineae93f62019-11-11 09:01:04 -0800172 return impl.read(b, off, len);
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000173 } finally {
174 profiler.logSimpleTask(startTime, ProfilerTask.VFS_READ, name);
175 }
176 }
felly0c4379a2018-11-01 10:47:43 -0700177 }
178
Yun Pengd2920e32018-11-27 02:07:55 -0800179 private static final class ProfiledFileOutputStream extends FileOutputStream {
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000180 private final String name;
181
Yun Pengd2920e32018-11-27 02:07:55 -0800182 public ProfiledFileOutputStream(String name, boolean append) throws FileNotFoundException {
183 super(name, append);
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000184 this.name = name;
185 }
186
187 @Override
188 public void write(byte[] b) throws IOException {
189 write(b, 0, b.length);
190 }
191
192 @Override
193 public void write(byte[] b, int off, int len) throws IOException {
194 long startTime = Profiler.nanoTimeMaybe();
195 try {
Yun Pengd2920e32018-11-27 02:07:55 -0800196 super.write(b, off, len);
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000197 } finally {
198 profiler.logSimpleTask(startTime, ProfilerTask.VFS_WRITE, name);
199 }
200 }
201 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100202}