blob: 16848c203acea60bea28917689ec91f07a8ff969 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 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.
14package com.google.devtools.build.lib.vfs;
15
16import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
17import com.google.devtools.build.lib.profiler.Profiler;
18import com.google.devtools.build.lib.profiler.ProfilerTask;
ccalvarinc2f18962018-08-22 15:08:40 -070019import com.google.devtools.build.lib.vfs.DigestHashFunction.DefaultHashFunctionNotSetException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020import java.io.FileInputStream;
21import java.io.FileNotFoundException;
22import java.io.FileOutputStream;
23import java.io.IOException;
24import java.io.InputStream;
25import java.io.OutputStream;
26
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000027/** This class implements the FileSystem interface using direct calls to the UNIX filesystem. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010028@ThreadSafe
shahanb1dd4e32018-05-09 08:23:31 -070029public abstract class AbstractFileSystem extends FileSystem {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010030
31 protected static final String ERR_PERMISSION_DENIED = " (Permission denied)";
32 protected static final Profiler profiler = Profiler.instance();
33
ccalvarinc2f18962018-08-22 15:08:40 -070034 public AbstractFileSystem() throws DefaultHashFunctionNotSetException {}
ccalvarinc9efd062018-07-27 12:46:46 -070035
ccalvarinbda12a12018-06-21 18:57:26 -070036 public AbstractFileSystem(DigestHashFunction digestFunction) {
buchgr559a07d2017-11-30 11:09:35 -080037 super(digestFunction);
38 }
39
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010040 @Override
aehligc801c392017-12-19 07:12:25 -080041 protected InputStream getInputStream(Path path) throws IOException {
Googler89100872016-07-26 15:52:48 +000042 // This loop is a workaround for an apparent bug in FileInputStream.open, which delegates
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010043 // ultimately to JVM_Open in the Hotspot JVM. This call is not EINTR-safe, so we must do the
44 // retry here.
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000045 for (; ; ) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046 try {
47 return createFileInputStream(path);
48 } catch (FileNotFoundException e) {
49 if (e.getMessage().endsWith("(Interrupted system call)")) {
50 continue;
51 } else {
52 throw e;
53 }
54 }
55 }
56 }
57
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000058 /** Returns either normal or profiled FileInputStream. */
Laszlo Csomor1a955022018-09-07 07:53:51 -070059 private InputStream createFileInputStream(Path path) throws IOException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010060 final String name = path.toString();
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000061 if (profiler.isActive()
62 && (profiler.isProfiling(ProfilerTask.VFS_READ)
63 || profiler.isProfiling(ProfilerTask.VFS_OPEN))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010064 long startTime = Profiler.nanoTimeMaybe();
65 try {
66 // Replace default FileInputStream instance with the custom one that does profiling.
Laszlo Csomor1a955022018-09-07 07:53:51 -070067 return new ProfiledFileInputStream(name, newFileInputStream(name));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010068 } finally {
69 profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
70 }
71 } else {
72 // Use normal FileInputStream instance if profiler is not enabled.
Laszlo Csomor1a955022018-09-07 07:53:51 -070073 return newFileInputStream(name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074 }
75 }
76
Laszlo Csomor1a955022018-09-07 07:53:51 -070077 protected InputStream newFileInputStream(String path) throws IOException {
78 return new FileInputStream(path);
79 }
80
81 protected OutputStream newFileOutputStream(String path, boolean append) throws IOException {
82 return new FileOutputStream(path, append);
83 }
84
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010085 /**
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000086 * Returns either normal or profiled FileOutputStream. Should be used by subclasses to create
87 * default OutputStream instance.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010088 */
Laszlo Csomor1a955022018-09-07 07:53:51 -070089 protected OutputStream createFileOutputStream(Path path, boolean append) throws IOException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010090 final String name = path.toString();
Laszlo Csomor3be9fd32016-10-26 09:32:54 +000091 if (profiler.isActive()
92 && (profiler.isProfiling(ProfilerTask.VFS_WRITE)
93 || profiler.isProfiling(ProfilerTask.VFS_OPEN))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010094 long startTime = Profiler.nanoTimeMaybe();
95 try {
Laszlo Csomor1a955022018-09-07 07:53:51 -070096 return new ProfiledFileOutputStream(name, newFileOutputStream(name, append));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010097 } finally {
98 profiler.logSimpleTask(startTime, ProfilerTask.VFS_OPEN, name);
99 }
100 } else {
Laszlo Csomor1a955022018-09-07 07:53:51 -0700101 return newFileOutputStream(name, append);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100102 }
103 }
104
105 @Override
aehligc801c392017-12-19 07:12:25 -0800106 protected OutputStream getOutputStream(Path path, boolean append) throws IOException {
tomlu22c2f9a2018-01-09 13:52:13 -0800107 try {
108 return createFileOutputStream(path, append);
109 } catch (FileNotFoundException e) {
110 // Why does it throw a *FileNotFoundException* if it can't write?
111 // That does not make any sense! And its in a completely different
112 // format than in other situations, no less!
113 if (e.getMessage().equals(path + ERR_PERMISSION_DENIED)) {
114 throw new FileAccessException(e.getMessage());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100115 }
tomlu22c2f9a2018-01-09 13:52:13 -0800116 throw e;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100117 }
118 }
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000119
Laszlo Csomor1a955022018-09-07 07:53:51 -0700120 private static final class ProfiledFileInputStream extends InputStream {
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000121 private final String name;
Laszlo Csomor1a955022018-09-07 07:53:51 -0700122 private final InputStream stm;
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000123
Laszlo Csomor1a955022018-09-07 07:53:51 -0700124 public ProfiledFileInputStream(String name, InputStream stm) {
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000125 this.name = name;
Laszlo Csomor1a955022018-09-07 07:53:51 -0700126 this.stm = stm;
127 }
128
129 @Override
130 public int available() throws IOException {
131 return stm.available();
132 }
133
134 @Override
135 public void close() throws IOException {
136 stm.close();
137 }
138
139 @Override
140 public void mark(int readlimit) {
141 stm.mark(readlimit);
142 }
143
144 @Override
145 public boolean markSupported() {
146 return stm.markSupported();
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000147 }
148
149 @Override
150 public int read() throws IOException {
151 long startTime = Profiler.nanoTimeMaybe();
152 try {
gregcee98f3442017-12-20 16:24:25 -0800153 // Note that FileInputStream#read() does *not* call any of our overridden methods,
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000154 // so there's no concern with double counting here.
Laszlo Csomor1a955022018-09-07 07:53:51 -0700155 return stm.read();
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000156 } finally {
157 profiler.logSimpleTask(startTime, ProfilerTask.VFS_READ, name);
158 }
159 }
160
161 @Override
162 public int read(byte[] b) throws IOException {
163 return read(b, 0, b.length);
164 }
165
166 @Override
167 public int read(byte[] b, int off, int len) throws IOException {
168 long startTime = Profiler.nanoTimeMaybe();
169 try {
Laszlo Csomor1a955022018-09-07 07:53:51 -0700170 return stm.read(b, off, len);
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000171 } finally {
172 profiler.logSimpleTask(startTime, ProfilerTask.VFS_READ, name);
173 }
174 }
Laszlo Csomor1a955022018-09-07 07:53:51 -0700175
176 @Override
177 public void reset() throws IOException {
178 stm.reset();
179 }
180
181 @Override
182 public long skip(long n) throws IOException {
183 return stm.skip(n);
184 }
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000185 }
186
Laszlo Csomor1a955022018-09-07 07:53:51 -0700187 private static final class ProfiledFileOutputStream extends OutputStream {
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000188 private final String name;
Laszlo Csomor1a955022018-09-07 07:53:51 -0700189 private final OutputStream stm;
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000190
Laszlo Csomor1a955022018-09-07 07:53:51 -0700191 public ProfiledFileOutputStream(String name, OutputStream stm) {
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000192 this.name = name;
Laszlo Csomor1a955022018-09-07 07:53:51 -0700193 this.stm = stm;
194 }
195
196 @Override
197 public void close() throws IOException {
198 stm.close();
199 }
200
201 @Override
202 public void flush() throws IOException {
203 stm.flush();
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000204 }
205
206 @Override
207 public void write(byte[] b) throws IOException {
208 write(b, 0, b.length);
209 }
210
211 @Override
212 public void write(byte[] b, int off, int len) throws IOException {
213 long startTime = Profiler.nanoTimeMaybe();
214 try {
Laszlo Csomor1a955022018-09-07 07:53:51 -0700215 stm.write(b, off, len);
216 } finally {
217 profiler.logSimpleTask(startTime, ProfilerTask.VFS_WRITE, name);
218 }
219 }
220
221 @Override
222 public void write(int b) throws IOException {
223 long startTime = Profiler.nanoTimeMaybe();
224 try {
225 stm.write(b);
Laszlo Csomor3be9fd32016-10-26 09:32:54 +0000226 } finally {
227 profiler.logSimpleTask(startTime, ProfilerTask.VFS_WRITE, name);
228 }
229 }
230 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100231}