On Wed, 29 Apr 2026 23:24:38 GMT, Ashay Rane <[email protected]> wrote:

> On Linux, various `stat()` calls allow probing information about files
> without opening them, but until recently, there wasn't an equivalent API
> available on Windows.  Now that `GetFileInformationByName()` exists,
> we can use it instead of `GetFileInformationByHandle()`, which required
> first opening the file to create a file handle, then reading the file
> attributes, and finally closing the file handle.
> 
> Since `GetFileInformationByName()` is available on only newer versions
> of Windows, this patch uses conditional compilation and `LoadLibrary()`
> + `GetProcAddress()` to dynamically set the pointer to the API function.
> If the dynamic loading fails, we fall back to the old API.  To avoid
> problems with race conditions, we use Windows' `INIT_ONCE` and
> `InitOnceExecuteOnce()` to initialize the function pointer exactly once.
> 
> The rest of the patch is similar to the addition of any new JNI function
> call.  WindowsConstants.java adds the relevant flags and error codes,
> WindowsFileAttributes.java adds the Java entry point,
> WindowsNativeDispatcher.java links the Java function with the C
> function, and WindowsNativeDispatcher.c calls the Win32 API function.
> 
> ---------
> - [x] I confirm that I make this contribution in accordance with the [OpenJDK 
> Interim AI Policy](https://openjdk.org/legal/ai).

Parts of this patch were derived from looking up a similar patch (PR 102149) 
for CPython (https://github.com/python/cpython) repository.

Here is a first pass at a JMH benchmark to show performance improvements.  This 
was run on a Windows/AArch64 machine.  Results follow.


package org.openjdk.bench.java.nio.file;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
@Fork(value = 3, jvmArgsAppend = {"-Dsun.nio.fs.ensureAccurateMetadata=true"})
@Warmup(iterations = 5, time = 2)
@Measurement(iterations = 5, time = 2)
public class FileAttributes {

    Path file;

    @Setup(Level.Trial)
    public void setup() throws IOException {
        file = Files.createTempFile("bench-attrs-", ".tmp");
    }

    @TearDown(Level.Trial)
    public void cleanup() throws IOException {
        Files.deleteIfExists(file);
    }

    @Benchmark
    public BasicFileAttributes followLinks() throws IOException {
        return Files.readAttributes(file, BasicFileAttributes.class);
    }

    @Benchmark
    public BasicFileAttributes noFollowLinks(Blackhole bh) throws IOException {
        for (Path f : files) {
            bh.consume(Files.readAttributes(f, BasicFileAttributes.class,
                                            LinkOption.NOFOLLOW_LINKS));
        }
    }
}


Results:


== before ==

Benchmark                     Mode  Cnt   Score   Error  Units
FileAttributes.followLinks    avgt   15  22.107   1.976  us/op
FileAttributes.noFollowLinks  avgt   15  21.425   1.780  us/op


== after ==
Benchmark                     Mode  Cnt  Score   Error  Units
FileAttributes.followLinks    avgt   15  7.085   0.570  us/op
FileAttributes.noFollowLinks  avgt   15  7.141   0.648  us/op

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

PR Comment: https://git.openjdk.org/jdk/pull/30994#issuecomment-4348241548

Reply via email to