Skip to content

Commit b5fee8e

Browse files
committed
Implement FileSystemUtils.copyFile via Files.copy if possible
`Files.copy` uses various optimizations such as kernel buffers (`sendfile` on Unix) or copy-on-write (`clonefile` on macOS, `copy_file_range` on Linux with a supported file system).
1 parent 6e80cbe commit b5fee8e

File tree

4 files changed

+28
-9
lines changed

4 files changed

+28
-9
lines changed

src/main/java/com/google/devtools/build/lib/vfs/AbstractFileSystem.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//
1515
package com.google.devtools.build.lib.vfs;
1616

17+
import static com.google.common.base.Preconditions.checkNotNull;
1718
import static java.nio.file.StandardOpenOption.CREATE;
1819
import static java.nio.file.StandardOpenOption.READ;
1920
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
@@ -62,7 +63,7 @@ public InputStream getInputStream(PathFragment path) throws IOException {
6263

6364
/** Allows the mapping of PathFragment to InputStream to be overridden in subclasses. */
6465
protected InputStream createFileInputStream(PathFragment path) throws IOException {
65-
return new FileInputStream(getIoFile(path));
66+
return new FileInputStream(checkNotNull(getIoFile(path)));
6667
}
6768

6869
/** Returns either normal or profiled FileInputStream. */

src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -797,21 +797,21 @@ public abstract void createFSDependentHardLink(PathFragment linkPath, PathFragme
797797
public void prefetchPackageAsync(PathFragment path, int maxDirs) {}
798798

799799
/**
800-
* Returns a {@link File} object for the given path. This method is only supported by file system
801-
* implementations that are backed by the local file system.
800+
* Returns a {@link File} object for the given path or null if this file system implementation is
801+
* not backed by the local file system.
802802
*/
803+
@Nullable
803804
public File getIoFile(PathFragment path) {
804-
throw new UnsupportedOperationException(
805-
"getIoFile() not supported for " + getClass().getName());
805+
return null;
806806
}
807807

808808
/**
809-
* Returns a {@link java.nio.file.Path} object for the given path. This method is only supported
810-
* by file system implementations that are backed by the local file system.
809+
* Returns a {@link java.nio.file.Path} object for the given path or null if this file system
810+
* implementation is not backed by the local file system.
811811
*/
812+
@Nullable
812813
public java.nio.file.Path getNioPath(PathFragment path) {
813-
throw new UnsupportedOperationException(
814-
"getNioPath() not supported for " + getClass().getName());
814+
return null;
815815
}
816816

817817
// Mapping from FileSystemException reason strings on various platforms to the corresponding Unix

src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
// limitations under the License.
1414
package com.google.devtools.build.lib.vfs;
1515

16+
import static com.google.devtools.build.lib.vfs.FileSystem.translateNioToIoException;
1617
import static java.nio.charset.StandardCharsets.ISO_8859_1;
18+
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
19+
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
1720

1821
import com.google.common.base.Preconditions;
1922
import com.google.common.collect.ImmutableList;
@@ -374,6 +377,18 @@ public static ByteSink asByteSink(final Path path) {
374377
*/
375378
@ThreadSafe // but not atomic
376379
public static void copyFile(Path from, Path to) throws IOException {
380+
var fromNio = from.getFileSystem().getNioPath(from.asFragment());
381+
var toNio = to.getFileSystem().getNioPath(to.asFragment());
382+
if (fromNio != null && toNio != null) {
383+
// Fast path: Files.copy uses various optimizations such as kernel buffers (sendfile on Unix)
384+
// or copy-on-write (clonefile on macOS, copy_file_range on Linux with a supported file system).
385+
try {
386+
java.nio.file.Files.copy(fromNio, toNio, REPLACE_EXISTING, COPY_ATTRIBUTES);
387+
} catch (IOException e) {
388+
throw translateNioToIoException(from.asFragment(), e);
389+
}
390+
return;
391+
}
377392
try {
378393
to.delete();
379394
} catch (IOException e) {

src/main/java/com/google/devtools/build/lib/vfs/PathTransformingDelegateFileSystem.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.io.OutputStream;
2525
import java.nio.channels.SeekableByteChannel;
2626
import java.util.Collection;
27+
import javax.annotation.Nullable;
2728

2829
/**
2930
* FileSystem implementation which delegates all operations to a provided instance with a
@@ -305,11 +306,13 @@ public void prefetchPackageAsync(PathFragment path, int maxDirs) {
305306
delegateFs.prefetchPackageAsync(toDelegatePath(path), maxDirs);
306307
}
307308

309+
@Nullable
308310
@Override
309311
public File getIoFile(PathFragment path) {
310312
return delegateFs.getIoFile(toDelegatePath(path));
311313
}
312314

315+
@Nullable
313316
@Override
314317
public java.nio.file.Path getNioPath(PathFragment path) {
315318
return delegateFs.getNioPath(toDelegatePath(path));

0 commit comments

Comments
 (0)