RFR: 8264744: (fc, fs) Support file cloning in Unix versions of FileChannel transfer and Files copy methods

Brian Burkhalter bpb at openjdk.org
Thu Jul 14 17:23:44 UTC 2022


On Wed, 13 Jul 2022 23:25:00 GMT, Brian Burkhalter <bpb at openjdk.org> wrote:

> Add file cloning to `java.nio.channels.FileChannel::transferTo` and `java.nio.file.Files.copy(Path,Path)`.

On Linux, the `copy_file_range(2)` system call already includes file cloning if available, so there is no need to add an explicit call to `ioctl(2)` with request code `FICLONE` or `FICLONERANGE` unless `copy_file_range()` is unavailable. Therefore the Linux `ioctl_ficlone` branch in `cloneFile0()` is conditional, and an invocation of `copy_file_range()` is prepended in `directCopy0()` on Linux. Note that as `FileChannel::transferFrom` was already calling `copy_file_range()`, it was already using cloning on Linux when possible.

On macOS, the available cloning system calls are `clonefile(2)` and `copyfile(3)` with for the latter `COPYFILE_CLONE` set in `flags`. There is no cloning call which accepts file descriptors as the target cannot already exist when the system call is invoked. There is also no call on macOS to clone a range of a file, hence there is no cloning added for `transferFrom()` nor `transferTo()` on macOS.

The througput of `Files::copy` is greatly increased by using cloning, at the expense of course of the first subsequent write to the target path being slower due to copy-on-write (CoW).

                            throughput (ops/s)
                APFS (macOS)         BTRFS (Linux)         EXT4 (Linux)
count         before   after       before   after        before   after
10240        1578.971 2902.128   24331.624 31074.073   27722.815 27574.891
51200        1849.027 2917.996   19295.797 31313.13    18590.463 18650.098
102400       1757.527 2899.018   15874.133 31243.225   13242.939 13235.246
512000       1195.215 2818.547    5856.964 30972.607    3998.696  3903.092
1048568       829.433 2169.738    3283.841 31097.633    2056.693  2014.939
10485760      126.736 2336.032     236.58  30754.849    154.103    153.356
104857600      15.014 2361.208      22.352 31123.14      14.864     14.746
1073741824      2.484 2335.799       1.549 30682.197      1.408      1.41

The throughput within a CoW file system (APFS and BTRFS) is much higher, especially for large files, and that within a non-CoW file system (EXT4) is effectively unchanged.

As APFS supports CoW, existing tests should cover these changes. For Linux, a dynamic search for file systems supporting CoW is added in the `CopyAndMove` test.

It is unclear whether the Linux branch in `cloneFile0` should attempt to use `ioctl_ficlone` if `copy_file_range` is undefined, as currently proposed, or simply always return `IOS_UNAVAILABLE`. It is likewise unclear whether `ioctl_ficlonerange` should be used in `transferFrom0` and `transferTo0` if `copy_file_range` is undefined (it currently is not).

In the initial version of this patch, cloning is enabled by default. In the issue description the possibility of adding a (JDK-specific?) `CopyOption` or system property to disable cloning was mentioned. There is also the opposite approach of cloning being disabled by default, with a `CopyOption` or system property required to enable it.

-------------

PR: https://git.openjdk.org/jdk/pull/9486


More information about the nio-dev mailing list