OpenHFT / Chronicle-Map

Replicate your Key Value Store across your network, with consistency, persistance and performance.
http://chronicle.software/products/chronicle-map/
Apache License 2.0
2.77k stars 469 forks source link

"java.io.IOException: posix_fallocate() returned -1" returned by ChronicleMapBuilder.createPersistedTo #540

Closed plbpietrz-chronicle closed 2 months ago

plbpietrz-chronicle commented 4 months ago

When trying to create a new ChronicleMap within a Ubuntu 22.04 docker container (and on bare metal Fedora 38, 39) we are seeing this IOException:

Caused by: java.io.IOException: posix_fallocate() returned -1
    at net.openhft.chronicle.hash.impl.util.jna.PosixFallocate.fallocate(PosixFallocate.java:20) ~[chronicle-map-3.25ea6.jar:3.25ea6]
    at net.openhft.chronicle.hash.impl.VanillaChronicleHash.fallocate(VanillaChronicleHash.java:1107) ~[chronicle-map-3.25ea6.jar:3.25ea6]
    at net.openhft.chronicle.hash.impl.VanillaChronicleHash.map(VanillaChronicleHash.java:1093) ~[chronicle-map-3.25ea6.jar:3.25ea6]
    at net.openhft.chronicle.hash.impl.VanillaChronicleHash.createMappedStoreAndSegments(VanillaChronicleHash.java:514) ~[chronicle-map-3.25ea6.jar:3.25ea6]
    at net.openhft.chronicle.map.ChronicleMapBuilder.createWithNewFile(ChronicleMapBuilder.java:1849) ~[chronicle-map-3.25ea6.jar:3.25ea6]
    at net.openhft.chronicle.map.ChronicleMapBuilder.createWithFile(ChronicleMapBuilder.java:1747) ~[chronicle-map-3.25ea6.jar:3.25ea6]
    at net.openhft.chronicle.map.ChronicleMapBuilder.createPersistedTo(ChronicleMapBuilder.java:1588) ~[chronicle-map-3.25ea6.jar:3.25ea6]
    ...

A minimal repro project, composed of posix:2.25ea0 and chronicle-core:2.25ea10 libraries, containing:

...
public static void main(String[] args) throws IOException {
        File testFile = new File("testFile.txt");
        if (!testFile.exists())
            testFile.createNewFile();

        try (FileInputStream fis = new FileInputStream(testFile)) {
            FileDescriptor fd = fis.getFD();

            PosixAPI posix = PosixAPI.posix();
            System.out.println("fallocate=" + posix.fallocate(getNativeFileDescriptor(fd), OpenFlag.O_APPEND.value(), 0, 106496));
        }
    }
...

also ends up with a fallocate=-1 being returned. What is interesting is that this code works if we remove the asm:9.2 library from the classpath. Below is the full dep tree of the test project

[INFO] org.example:test-project:jar:1.0-SNAPSHOT
[INFO] +- net.openhft:posix:jar:2.25ea0:compile
[INFO] |  +- org.slf4j:slf4j-api:jar:1.7.36:compile
[INFO] |  +- net.java.dev.jna:jna:jar:5.5.0:compile
[INFO] |  +- net.java.dev.jna:jna-platform:jar:5.5.0:compile
[INFO] |  +- com.github.jnr:jnr-ffi:jar:2.2.13:compile
[INFO] |  |  +- com.github.jnr:jffi:jar:1.3.10:compile
[INFO] |  |  +- com.github.jnr:jffi:jar:native:1.3.10:runtime
[INFO] |  |  +- org.ow2.asm:asm:jar:9.2:compile
[INFO] |  |  +- com.github.jnr:jnr-a64asm:jar:1.0.0:compile
[INFO] |  |  \- com.github.jnr:jnr-x86asm:jar:1.0.2:compile
[INFO] |  \- com.github.jnr:jnr-constants:jar:0.10.4:compile
[INFO] \- net.openhft:chronicle-core:jar:2.25ea10:compile
[INFO]    \- net.openhft:chronicle-analytics:jar:2.25ea0:compile
rogersimmons commented 4 months ago

hi @plbpietrz-chronicle - running the minimal reproducer on an Ubuntu 22.04 VM there are 2 issues:

  1. In order to fallocate the file the associated descriptor must be in RDWR mode. As the file is opened with a FileInputStream it lacks the WR flag, which causes the fallocate to return an EBADF error.

  2. The OpenFlag.O_APPEND.value() does not pass the correct numerical value in this context (it's passing 8, which is the "collapse" option for fallocate). The correct numerical value here is 0.

Putting both fixes in place the minimal reproducer runs without issue. (The test file is created, and resized to 106496, with fallocate returning 0).

Could you double check the minimal reproducer and/or the original code it is base upon and let me know how things look.

Thanks

rogersimmons commented 4 months ago

For completeness, this is a working version: (FileInputStream -> FileOutputStream; 2nd arg OpenFlag.O_APPEND.value() -> 0)

    private static int getNativeFileDescriptor(FileDescriptor fd) {
        return SharedSecrets.getJavaIOFileDescriptorAccess().get(fd);
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        File testFile = new File("testFile.txt");
        if (!testFile.exists())
            testFile.createNewFile();

        try (FileOutputStream fis = new FileOutputStream(testFile)) {
            FileDescriptor fd = fis.getFD();

            PosixAPI posix = PosixAPI.posix();
            System.out.println("fallocate=" + posix.fallocate(getNativeFileDescriptor(fd), 0, 0, 106496));
        }
    }
plbpietrz-chronicle commented 4 months ago

Another example of the fallocate issue would be this chronicle-map example:

    public static void main(String[] args) throws IOException {
        try (ChronicleMap<String, Double> map = ChronicleMapBuilder.of(String.class, Double.class)
                .averageKeySize(256)
                    .entries(1024)
                    .name("chronicle-map")
                    .createPersistedTo(new File(".", "chronicle-map.cm3"));
        ) {
            System.out.println("Map created: " + map);
        }
    }

with only this library in mvn dependencies section:

<dependency>
    <groupId>net.openhft</groupId>
    <artifactId>chronicle-map</artifactId>
    <version>3.25ea5</version>
</dependency>
rogersimmons commented 4 months ago

The above works for me with unmodified Chronicle-Map ea on:

@plbpietrz-chronicle - as discussed, pls try a fresh VM of your distro (Fedora) and vanilla Chronicle-Map to rule out something awry in your local env.

plbpietrz-chronicle commented 2 months ago

Issue fixed in latest release