All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xerial.larray.mmap.MMapBuffer Maven / Gradle / Ivy

package xerial.larray.mmap;


import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Field;
import java.nio.channels.FileChannel;
import sun.misc.SharedSecrets;
import xerial.larray.buffer.LBufferAPI;
import xerial.larray.buffer.LBufferConfig;
import xerial.larray.buffer.UnsafeUtil;
import xerial.larray.impl.LArrayNative;
import xerial.larray.impl.OSInfo;

/**
 * Memory-mapped file buffer
 *
 * @author Taro L. Saito
 */
public class MMapBuffer extends LBufferAPI {

    private final RandomAccessFile raf;
    private final FileChannel fc;
    private final long fd;
    private final int pagePosition;

    private final long address;
    private long winHandle = -1;

    @Override
    public long address()  { return address; }

    /**
     * Open an memory mapped file.
     * @param f
     * @param mode
     * @throws IOException
     */
    public MMapBuffer(File f, MMapMode mode) throws IOException {
        this(f, 0L, f.length(), mode);
    }

    /**
     * Open an memory mapped file.
     * @param f
     * @param offset
     * @param size
     * @param mode
     * @throws IOException
     */
    public MMapBuffer(File f, long offset, long size, MMapMode mode) throws IOException {
        super();
        this.raf = new RandomAccessFile(f, mode.mode);
        this.fc = raf.getChannel();
        // Retrieve file descriptor
        FileDescriptor rawfd = raf.getFD();
        try {
            if(!OSInfo.isWindows()) {
                Field idf = rawfd.getClass().getDeclaredField("fd");
                idf.setAccessible(true);
                this.fd = idf.getInt(rawfd);
            }
            else {
                // In Windows, fd is stored as 'handle'
                Field idf = rawfd.getClass().getDeclaredField("handle");
                idf.setAccessible(true);
                this.fd = idf.getLong(rawfd);
            }
        }
        catch(Exception e) {
            throw new IOException("Failed to retrieve file descriptor of " + f.getPath() + ": " + e.getMessage());
        }

        long allocationGranule = UnsafeUtil.unsafe.pageSize();
        this.pagePosition = (int) (offset % allocationGranule);

        // Compute mmap address
        if(!fc.isOpen())
            throw new IOException("closed " + f.getPath());

        long fileSize = fc.size();
        if(fileSize < offset + size) {
            // If file size is smaller than the specified size, extend the file size
            raf.seek(offset + size - 1);
            raf.write(0);
            //logger.trace(s"extend file size to ${fc.size}")
        }
        long mapPosition = offset - pagePosition;
        long mapSize = size + pagePosition;
        // A workaround for the error when calling fc.map(MapMode.READ_WRITE, offset, size) with size more than 2GB

        long rawAddr = LArrayNative.mmap(fd, mode.code, mapPosition, mapSize);
        //trace(f"mmap addr:$rawAddr%x, start address:${rawAddr+pagePosition}%x")

        if(OSInfo.isWindows()) {
            sun.misc.JavaIOFileDescriptorAccess a = SharedSecrets.getJavaIOFileDescriptorAccess();
            winHandle = LArrayNative.duplicateHandle(a.getHandle(raf.getFD()));
            //debug(f"win handle: $winHandle%x")
        }

        this.m = new MMapMemory(rawAddr, mapSize);
        LBufferConfig.allocator.register(m);

        this.address = rawAddr + pagePosition;
    }

    /**
     * Forces any changes made to this buffer to be written to the file
     */
    public void flush() {
        LArrayNative.msync(winHandle, m.headerAddress(), m.size());
    }

    /**
     * Close the memory mapped file. To ensure the written data is saved in the file, call flush before closing.
     */
    public void close() throws IOException {
        release();
        fc.close();
    }

    protected long offset() {
        return pagePosition;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy