jankotek / mapdb

MapDB provides concurrent Maps, Sets and Queues backed by disk storage or off-heap-memory. It is a fast and easy to use embedded Java database engine.
https://mapdb.org
Apache License 2.0
4.87k stars 873 forks source link

mapdb 3.0.8 fails to fileLoad mapDB file when readOnly set #1012

Open stevenwernercs opened 1 year ago

stevenwernercs commented 1 year ago

fileLoad() of mapDBfile fails when DBMaker is set to readOnly, fileLoad() succeeds if not readOnly

java.lang.UnsupportedOperationException: null
    at java.nio.MappedByteBuffer.checkMapped(MappedByteBuffer.java:96) ~[?:1.8.0_302]
    at java.nio.MappedByteBuffer.load(MappedByteBuffer.java:156) ~[?:1.8.0_302]
    at org.mapdb.volume.MappedFileVolSingle.fileLoad(MappedFileVolSingle.java:173) ~[mapdb-3.0.8.jar:?]
    at org.mapdb.StoreDirect.fileLoad(StoreDirect.kt:1112) ~[mapdb-3.0.8.jar:?]
    at <our code that calls db_.getStore().fileLoad();   see below>

our calling code:

//it used STRING & JAVA for key & value serializers respectively to create the file, and the file was committed & closed                     
                    DB db = DBMaker
                            .fileDB(file)
                            .fileMmapEnableIfSupported()
                            .fileMmapPreclearDisable()
                            .fileChannelEnable()
                            .cleanerHackEnable()
                            .closeOnJvmShutdown()
                            .readOnly()    //only fails when this is uncommented, seems you cant load a file if you set it to readOnly
                            .make();

                    db.getStore().fileLoad();  <-- fails here

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/nio/MappedByteBuffer.java the comment is in the java source, and it is exactly what the mapdb code is doing

    private void checkMapped() {
        if (fd == null)
            // Can only happen if a luser explicitly casts a direct byte buffer
            throw new UnsupportedOperationException();
    }

https://github.com/jankotek/mapdb/blob/release-3.0/src/main/java/org/mapdb/volume/MappedFileVolSingle.java

...Constructor:
            buffer = raf.getChannel().map(mapMode, 0, maxSize);    //this returns a  DirectByteBuffer extends MappedByteBuffer
                                                          //but its call to super() does seem to set the fd for java 8, or is done at the asReadOnlyBuffer copy
            if (readOnly)
                buffer = buffer.asReadOnlyBuffer();   //this calls an ByteBuffer abstract method, but the caller never sets the fd value (MappedByteBuffer has 2 constructors, one that sets fd & one that doesnt, control flow is obscured but its calling the one where fd=null, thus is not mapped
...
    @Override
    public boolean fileLoad() {
        ((MappedByteBuffer) buffer).load();
        return true;
    }