Package xbird.util.nio

Source Code of xbird.util.nio.MemoryMappedFile

/*
* @(#)$Id$
*
* Copyright 2006-2008 Makoto YUI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
*     Makoto YUI - initial implementation
*/
package xbird.util.nio;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.Map;

import xbird.config.Settings;
import xbird.server.services.RemotePagingService;
import xbird.util.collections.ObservableLRUMap;
import xbird.util.collections.ObservableLRUMap.Cleaner;
import xbird.util.concurrent.AtomicUtils;
import xbird.util.io.IOUtils;
import xbird.util.struct.MutableLongPair;

/**
*
* <DIV lang="en"></DIV> <DIV lang="ja"></DIV>
*
* @author Makoto YUI (yuin405+xbird@gmail.com)
*/
public final class MemoryMappedFile implements IMemoryMappedFile {
    private static final int MAX_MAPPED_BUFS = Integer.parseInt(Settings.get("xbird.database.mmap.max_mapped", "2048"));

    // controls
    private final boolean _readOnly;
    private final boolean _setAsLittleEndian;
    private final int _pageSize;

    private final long _oid;

    private transient final String _filepath;
    private FileChannel _channel;

    private static final Map<MutableLongPair, CloseableMappedByteBuffer> _pool;
    static {
        final Cleaner<MutableLongPair, CloseableMappedByteBuffer> cleaner = new Cleaner<MutableLongPair, CloseableMappedByteBuffer>() {
            public void cleanup(MutableLongPair key, CloseableMappedByteBuffer reclaimed) {
                try {
                    reclaimed.close();
                } catch (IOException e) {
                    ;
                }
            }
        };
        _pool = new ObservableLRUMap<MutableLongPair, CloseableMappedByteBuffer>(MAX_MAPPED_BUFS, cleaner);
    }

    /**
     * @param pageSize should be greater than or equals to 64k.
     */
    public MemoryMappedFile(final File file, final int pageShift, final boolean readOnly, final boolean nativeByteOrder)
            throws FileNotFoundException {
        this._filepath = file.getAbsolutePath();
        RandomAccessFile raf = new RandomAccessFile(file, readOnly ? "r" : "rw");
        this._channel = raf.getChannel();
        this._readOnly = readOnly;
        this._setAsLittleEndian = nativeByteOrder
                && (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN);
        this._pageSize = 1 << pageShift;

        this._oid = System.identityHashCode(this);
    }

    public CloseableMappedByteBuffer allocateBuffer(final long pageOffset) {
        final MutableLongPair pair = new MutableLongPair(_oid, pageOffset);
        final Map<MutableLongPair, CloseableMappedByteBuffer> pool = _pool;
        CloseableMappedByteBuffer buf;
        synchronized(pool) {
            buf = pool.get(pair);
            if(buf == null || !AtomicUtils.tryIncrementIfGreaterThan(buf.referenceCount(), 0)) {
                MappedByteBuffer bufimpl = map(pageOffset);
                buf = new CloseableMappedByteBuffer(bufimpl);
                pool.put(pair, buf);
            }
        }
        return buf;
    }

    /**
     * @link http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038
     */
    private MappedByteBuffer map(final long page) {
        if(_channel == null) {
            ensureOpen();
        }
        MappedByteBuffer buf;
        try {
            buf = _channel.map(_readOnly ? MapMode.READ_ONLY : MapMode.READ_WRITE, page, _pageSize);
        } catch (IOException e) {// silly workaround for JDK bug #4724038
            System.gc();
            System.runFinalization();
            try {
                buf = _channel.map(_readOnly ? MapMode.READ_ONLY : MapMode.READ_WRITE, page, _pageSize);
            } catch (IOException ioe) {
                throw new IllegalStateException("map failed for page#" + page + " of file: "
                        + _filepath, ioe);
            }
        }
        if(_setAsLittleEndian) {// BIG_ENDIAN by the default
            buf.order(ByteOrder.LITTLE_ENDIAN);
        }
        return buf;
    }

    public int[] transferBuffer(final long pageOffset, final int aryLength) {
        final int[] newPage = new int[aryLength];
        final CloseableMappedByteBuffer buf = allocateBuffer(pageOffset);
        final IntBuffer ibuf = buf.getBuffer().asIntBuffer();
        ibuf.get(newPage, 0, aryLength);
        IOUtils.closeQuietly(buf);
        return newPage;
    }

    public synchronized void flush() {
        _pool.clear();
    }

    public synchronized void close() throws IOException {
        _channel.close();
        this._channel = null;
    }

    public synchronized void ensureOpen() {
        if(_channel == null) {
            final RandomAccessFile raf;
            try {
                raf = new RandomAccessFile(_filepath, _readOnly ? "r" : "rw");
            } catch (FileNotFoundException e) {
                throw new IllegalStateException("File not found: " + _filepath, e);
            }
            this._channel = raf.getChannel();
        }
    }

    public RemoteMemoryMappedFile externalize() {
        return new RemoteMemoryMappedFile(RemotePagingService.PORT, _filepath, _pageSize, false, !_setAsLittleEndian);
    }

}
TOP

Related Classes of xbird.util.nio.MemoryMappedFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.