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

com.tangosol.io.nio.MappedBufferManager Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2021, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */

package com.tangosol.io.nio;


import com.tangosol.util.Base;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import java.lang.reflect.Method;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;


/**
* Manages a ByteBuffer on a file.
*
* @see ByteBuffer
*
* @author cp  2002.09.18
*
* @since Coherence 2.2
*/
public class MappedBufferManager
        extends AbstractBufferManager
    {
    // ----- constructors ---------------------------------------------------

    /**
    * Construct a MappedBufferManager using defaults.
    */
    public MappedBufferManager()
        {
        this(DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE, null);
        }

    /**
    * Construct a MappedBufferManager that supports a buffer of a certain
    * initial and maximum size.
    *
    * @param cbInitial  the initial size
    * @param cbMaximum  the maximum size
    * @param file       the file to use, or the directory to use, or null
    *                   to generate a temporary file in the default location
    */
    public MappedBufferManager(int cbInitial, int cbMaximum, File file)
        {
        super(cbInitial, cbMaximum);
        configureFile(file);
        allocateBuffer();
        }


    // ----- internal -------------------------------------------------------

    /**
    * Configure the buffer manager based on the passed file, which may be
    * null to imply a default temp file, a directory to imply that a file
    * be created in that directory, or it may be the temp file itself.
    *
    * @param file  the file to use, or the directory to use, or null
    *              to generate a temporary file in the default location
    */
    protected void configureFile(File file)
        {
        try
            {
            boolean fTemp = false;

            // ensure the temp file, and if it is created here, make sure
            // it is registered for removal
            if (file == null || file.isDirectory())
                {
                file  = File.createTempFile("coherence", null, file);
                fTemp = true;
                }
            else if (!file.exists())
                {
                file.createNewFile();
                fTemp = true;
                }

            // configure random access to the file
            RandomAccessFile hfile = new RandomAccessFile(file, "rw");
            setFile(hfile);

            if (fTemp)
                {
                file.deleteOnExit();
                m_fileTemp = file;
                }
            }
        catch (IOException e)
            {
            throw Base.ensureRuntimeException(e);
            }
        }

    /**
    * Obtain the RandomAccessFile that the buffer is constructed on.
    *
    * @return the RandomAccessFile object
    */
    protected RandomAccessFile getFile()
        {
        return m_hfile;
        }

    /**
    * Specify the RandomAccessFile that the buffer will be constructed on.
    *
    * @param file  the RandomAccessFile object
    */
    protected void setFile(RandomAccessFile file)
        {
        m_hfile = file;
        }

    /**
    * Allocate a new buffer, copying old data if there is any.
    *
    * @see FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long) FileChannel.map()
    */
    protected void allocateBuffer()
        {
        try
            {
            RandomAccessFile hfile = getFile();

            int cbOld = (int) hfile.length();
            int cbNew = getCapacity();

            if (cbNew != cbOld)
                {
                setBuffer(null);

                // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4857305
                System.gc();
                Thread.yield();

                try
                    {
                    hfile.setLength(cbNew);
                    }
                catch (IOException e)
                    {
                    // only "worry" if the file cannot grow
                    if (cbNew > cbOld)
                        {
                        throw e;
                        }
                    }
                setBuffer(hfile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0L, cbNew));
                }
            }
        catch (IOException e)
            {
            throw Base.ensureRuntimeException(e);
            }
        }


    // ----- life-cycle support ---------------------------------------------

    /**
    * Close the underlying resources.
    */
    public void close()
        {
        try
            {
            RandomAccessFile hfile = m_hfile;
            if (hfile != null)
                {
                // need to close the file to have it deleted on exit:
                //   http://developer.java.sun.com/developer/bugParade/bugs/4171239.html
                // however, this may not work on Windows:
                //   http://developer.java.sun.com/developer/bugParade/bugs/4715154.html
                // attempt to unmap before close as suggested in the bug link above
                try
                    {
                    ByteBuffer buffer = getBuffer();
                    Method getCleanerMethod = buffer.getClass().getMethod("cleaner");
                    getCleanerMethod.setAccessible(true);
                    Object cleaner = getCleanerMethod.invoke(buffer);
                    Method cleanMethod = cleaner.getClass().getMethod("clean");
                    cleanMethod.invoke(cleaner);
                    }
                catch (Throwable t) {}

                hfile.close();
                }

            File fileTemp = m_fileTemp;
            if (fileTemp != null)
                {
                if (fileTemp.delete())
                    {
                    m_fileTemp = null;
                    }
                else
                    {
                    // Java BugID: 4715154; Closed, will not be fixed on windows
                    log("MappedBufferManager: " + "failed to remove " + fileTemp);
                    }
                }
            }
        catch (Exception e) {}

        m_hfile = null;
        }

    /**
    * Perform cleanup during garbage collection.
    */
    protected void finalize()
        {
        close();
        }


    // ----- constants ------------------------------------------------------

    /**
    * Default minimum size for a memory mapped file.
    */
    public static final int DEFAULT_MIN_SIZE  = 0x4000;

    /**
    * Default maximum size for a memory mapped file.
    */
    public static final int DEFAULT_MAX_SIZE  = Integer.MAX_VALUE;


    // ----- data members ---------------------------------------------------

    /**
    * The underlying temporary File.
    */
    private File m_fileTemp;

    /**
    * The underlying RandomAccessFile.
    */
    private RandomAccessFile m_hfile;
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy