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

org.mapdb.volume.ByteBufferVol Maven / Gradle / Ivy

package org.mapdb.volume;

import org.mapdb.CC;
import org.mapdb.DBException;
import org.mapdb.DataInput2;
import org.mapdb.volume.CleanerUtil;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Abstract Volume over bunch of ByteBuffers
 * It leaves ByteBufferVol details (allocation, disposal) on subclasses.
 * Most methods are final for better performance (JIT compiler can inline those).
 */
abstract public class ByteBufferVol extends Volume {

    protected final  boolean cleanerHackEnabled;

    protected final ReentrantLock growLock = new ReentrantLock();
    protected final int sliceShift;
    protected final int sliceSizeModMask;
    protected final int sliceSize;

    protected volatile ByteBuffer[] slices = new ByteBuffer[0];
    protected final boolean readOnly;

    protected ByteBufferVol(boolean readOnly, int sliceShift, boolean cleanerHackEnabled) {
        this.readOnly = readOnly;
        this.sliceShift = sliceShift;
        this.cleanerHackEnabled = cleanerHackEnabled;
        this.sliceSize = 1<< sliceShift;
        this.sliceSizeModMask = sliceSize -1;
    }


    protected final ByteBuffer getSlice(long offset){
        ByteBuffer[] slices = this.slices;
        int pos = (int)(offset >>> sliceShift);
        if(pos>=slices.length)
            throw new DBException.VolumeEOF("Get/Set beyond file size. Requested offset: "+offset+", volume size: "+length());
        return slices[pos];
    }

    @Override public final void putLong(final long offset, final long value) {
        if(CC.VOLUME_PRINT_STACK_AT_OFFSET!=0 && CC.VOLUME_PRINT_STACK_AT_OFFSET>=offset && CC.VOLUME_PRINT_STACK_AT_OFFSET <= offset+8){
            new IOException("VOL STACK:").printStackTrace();
        }

        getSlice(offset).putLong((int) (offset & sliceSizeModMask), value);
    }

    @Override public final void putInt(final long offset, final int value) {
        if(CC.VOLUME_PRINT_STACK_AT_OFFSET!=0 && CC.VOLUME_PRINT_STACK_AT_OFFSET>=offset && CC.VOLUME_PRINT_STACK_AT_OFFSET <= offset+4){
            new IOException("VOL STACK:").printStackTrace();
        }

        getSlice(offset).putInt((int) (offset & sliceSizeModMask), value);
    }


    @Override public final void putByte(final long offset, final byte value) {
        if(CC.VOLUME_PRINT_STACK_AT_OFFSET!=0 && CC.VOLUME_PRINT_STACK_AT_OFFSET>=offset && CC.VOLUME_PRINT_STACK_AT_OFFSET <= offset+1){
            new IOException("VOL STACK:").printStackTrace();
        }

        getSlice(offset).put((int) (offset & sliceSizeModMask), value);
    }



    @Override public void putData(final long offset, final byte[] src, int srcPos, int srcSize){
        if(CC.VOLUME_PRINT_STACK_AT_OFFSET!=0 && CC.VOLUME_PRINT_STACK_AT_OFFSET>=offset && CC.VOLUME_PRINT_STACK_AT_OFFSET <= offset+srcSize){
            new IOException("VOL STACK:").printStackTrace();
        }


        final ByteBuffer b1 = getSlice(offset).duplicate();
        final int bufPos = (int) (offset& sliceSizeModMask);

        b1.position(bufPos);
        b1.put(src, srcPos, srcSize);
    }


    @Override public final void putData(final long offset, final ByteBuffer buf) {
        if(CC.VOLUME_PRINT_STACK_AT_OFFSET!=0 && CC.VOLUME_PRINT_STACK_AT_OFFSET>=offset && CC.VOLUME_PRINT_STACK_AT_OFFSET <= offset+buf.remaining()){
            new IOException("VOL STACK:").printStackTrace();
        }

        final ByteBuffer b1 = getSlice(offset).duplicate();
        final int bufPos = (int) (offset& sliceSizeModMask);
        //no overlap, so just write the value
        b1.position(bufPos);
        b1.put(buf);
    }

    @Override
    public void copyTo(long inputOffset, Volume target, long targetOffset, long size) {
        final ByteBuffer b1 =getSlice(inputOffset).duplicate();
        final int bufPos = (int) (inputOffset& sliceSizeModMask);

        b1.position(bufPos);
        //TODO size>Integer.MAX_VALUE
        b1.limit((int) (bufPos+size));
        target.putData(targetOffset, b1);
    }

    @Override public void getData(final long offset, final byte[] src, int srcPos, int srcSize){
        final ByteBuffer b1 = getSlice(offset).duplicate();
        final int bufPos = (int) (offset& sliceSizeModMask);

        b1.position(bufPos);
        b1.get(src, srcPos, srcSize);
    }


    @Override final public long getLong(long offset) {
        return getSlice(offset).getLong((int) (offset & sliceSizeModMask));
    }

    @Override final public int getInt(long offset) {
        return getSlice(offset).getInt((int) (offset & sliceSizeModMask));
    }


    @Override public final byte getByte(long offset) {
        return getSlice(offset).get((int) (offset & sliceSizeModMask));
    }


    @Override
    public final DataInput2.ByteBuffer getDataInput(long offset, int size) {
        return new DataInput2.ByteBuffer(getSlice(offset), (int) (offset& sliceSizeModMask));
    }



    @Override
    public void putDataOverlap(long offset, byte[] data, int pos, int len) {
        boolean overlap = (offset>>>sliceShift != (offset+len)>>>sliceShift);

        if(overlap){
            while(len>0){
                ByteBuffer b = getSlice(offset).duplicate();
                b.position((int) (offset&sliceSizeModMask));

                int toPut = Math.min(len,sliceSize - b.position());

                b.limit(b.position()+toPut);
                b.put(data, pos, toPut);

                pos+=toPut;
                len-=toPut;
                offset+=toPut;
            }
        }else{
            putData(offset,data,pos,len);
        }
    }

    @Override
    public DataInput2 getDataInputOverlap(long offset, int size) {
        boolean overlap = (offset>>>sliceShift != (offset+size)>>>sliceShift);
        if(overlap){
            byte[] bb = new byte[size];
            final int origLen = size;
            while(size>0){
                ByteBuffer b = getSlice(offset).duplicate();
                b.position((int) (offset&sliceSizeModMask));

                int toPut = Math.min(size,sliceSize - b.position());

                b.limit(b.position()+toPut);
                b.get(bb,origLen-size,toPut);
                size -=toPut;
                offset+=toPut;
            }
            return new DataInput2.ByteArray(bb);
        }else{
            //return mapped buffer
            return getDataInput(offset,size);
        }
    }


    @Override
    public void putUnsignedShort(long offset, int value) {
        final ByteBuffer b = getSlice(offset);
        int bpos = (int) (offset & sliceSizeModMask);

        b.put(bpos++, (byte) (value >> 8));
        b.put(bpos, (byte) (value));
    }

    @Override
    public int getUnsignedShort(long offset) {
        final ByteBuffer b = getSlice(offset);
        int bpos = (int) (offset & sliceSizeModMask);

        return (( (b.get(bpos++) & 0xff) << 8) |
                ( (b.get(bpos) & 0xff)));
    }

    @Override
    public int getUnsignedByte(long offset) {
        final ByteBuffer b = getSlice(offset);
        int bpos = (int) (offset & sliceSizeModMask);

        return b.get(bpos) & 0xff;
    }

    @Override
    public void putUnsignedByte(long offset, int byt) {
        final ByteBuffer b = getSlice(offset);
        int bpos = (int) (offset & sliceSizeModMask);

        b.put(bpos, toByte(byt));
    }

    protected static byte toByte(int byt) {
        return (byte) (byt & 0xff);
    }


    protected static byte toByte(long l) {
        return (byte) (l & 0xff);
    }
    @Override
    public long getSixLong(long pos) {
        final ByteBuffer bb = getSlice(pos);
        int bpos = (int) (pos & sliceSizeModMask);

        return
                ((long) (bb.get(bpos++) & 0xff) << 40) |
                        ((long) (bb.get(bpos++) & 0xff) << 32) |
                        ((long) (bb.get(bpos++) & 0xff) << 24) |
                        ((long) (bb.get(bpos++) & 0xff) << 16) |
                        ((long) (bb.get(bpos++) & 0xff) << 8) |
                        ((long) (bb.get(bpos) & 0xff));
    }

    @Override
    public void putSixLong(long pos, long value) {
        final ByteBuffer b = getSlice(pos);
        int bpos = (int) (pos & sliceSizeModMask);

        if(CC.ASSERT && (value >>>48!=0))
            throw new DBException.DataCorruption("six long out of range");

        b.put(bpos++, (byte) (0xff & (value >> 40)));
        b.put(bpos++, (byte) (0xff & (value >> 32)));
        b.put(bpos++, (byte) (0xff & (value >> 24)));
        b.put(bpos++, (byte) (0xff & (value >> 16)));
        b.put(bpos++, (byte) (0xff & (value >> 8)));
        b.put(bpos, (byte) (0xff & (value)));
    }

    @Override
    public int putPackedLong(long pos, long value) {
        final ByteBuffer b = getSlice(pos);
        int bpos = (int) (pos & sliceSizeModMask);

        //$DELAY$
        int ret = 0;
        int shift = 63-Long.numberOfLeadingZeros(value);
        shift -= shift%7; // round down to nearest multiple of 7
        while(shift!=0){
            b.put(bpos + (ret++), (byte) (((value >>> shift) & 0x7F) ));
            //$DELAY$
            shift-=7;
        }
        b.put(bpos +(ret++),(byte) ((value & 0x7F) | 0x80));
        return ret;
    }

    @Override
    public long getPackedLong(long position) {
        final ByteBuffer b = getSlice(position);
        int bpos = (int) (position & sliceSizeModMask);

        long ret = 0;
        int pos2 = 0;
        byte v;
        do{
            v = b.get(bpos +(pos2++));
            ret = (ret<<7 ) | (v & 0x7F);
        }while((v&0x80)==0);

        return (((long)pos2)<<60) | ret;
    }

    @Override
    public void clear(long startOffset, long endOffset) {
        if(CC.ASSERT && (startOffset >>> sliceShift) != ((endOffset-1) >>> sliceShift))
            throw new AssertionError();
        ByteBuffer buf = getSlice(startOffset);
        int start = (int) (startOffset&sliceSizeModMask);
        int end = (int) (start+(endOffset-startOffset));

        int pos = start;
        while(pos




© 2015 - 2024 Weber Informatics LLC | Privacy Policy