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

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

Go to download

MapDB provides concurrent Maps, Sets and Queues backed by disk storage or off-heap memory. It is a fast, scalable and easy to use embedded Java database.

There is a newer version: 3.1.0
Show newest version
package org.mapdb.volume;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mapdb.CC;
import org.mapdb.DBException;
import org.mapdb.DataIO;
import org.mapdb.DataInput2;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by jan on 2/29/16.
 */
public final class ByteArrayVol extends Volume {

    public static final VolumeFactory FACTORY = new VolumeFactory() {

        @Override
        public Volume makeVolume(String file, boolean readOnly, long fileLockWait, int sliceShift, long initSize, boolean fixedSize) {
            //TODO optimize for fixedSize if bellow 2GB
            return new org.mapdb.volume.ByteArrayVol(sliceShift, initSize);
        }

        @NotNull
        @Override
        public boolean exists(@Nullable String file) {
            return false;
        }

        @Override
        public boolean handlesReadonly() {
            return false;
        }
    };

    protected final ReentrantLock growLock = new ReentrantLock();

    protected final int sliceShift;
    protected final int sliceSizeModMask;
    protected final int sliceSize;

    protected volatile byte[][] slices = new byte[0][];

    public ByteArrayVol() {
        this(CC.PAGE_SHIFT, 0L);
    }

    public ByteArrayVol(int sliceShift, long initSize) {
        this.sliceShift = sliceShift;
        this.sliceSize = 1 << sliceShift;
        this.sliceSizeModMask = sliceSize - 1;

        if (initSize != 0) {
            ensureAvailable(initSize);
        }
    }

    protected final byte[] getSlice(long offset) {
        byte[][] slices = this.slices;
        int pos = ((int) (offset >>> sliceShift));
        if (pos >= slices.length)
            throw new DBException.VolumeEOF("offset points beyond slices");
        return slices[pos];
    }

    @Override
    public final void ensureAvailable(long offset) {
        offset = DataIO.roundUp(offset, 1L << sliceShift);
        int slicePos = (int) (offset >>> sliceShift);

        //check for most common case, this is already mapped
        if (slicePos < slices.length) {
            return;
        }

        growLock.lock();
        try {
            //check second time
            if (slicePos <= slices.length)
                return;

            int oldSize = slices.length;
            byte[][] slices2 = slices;

            slices2 = Arrays.copyOf(slices2, slicePos);

            for (int pos = oldSize; pos < slices2.length; pos++) {
                slices2[pos] = new byte[sliceSize];
            }


            slices = slices2;
        } catch (OutOfMemoryError e) {
            throw new DBException.OutOfMemory(e);
        } finally {
            growLock.unlock();
        }
    }


    @Override
    public void truncate(long size) {
        final int maxSize = 1 + (int) (size >>> sliceShift);
        if (maxSize == slices.length)
            return;
        if (maxSize > slices.length) {
            ensureAvailable(size);
            return;
        }
        growLock.lock();
        try {
            if (maxSize >= slices.length)
                return;
            slices = Arrays.copyOf(slices, maxSize);
        } finally {
            growLock.unlock();
        }
    }

    @Override
    public void putLong(long offset, long v) {
        int pos = (int) (offset & sliceSizeModMask);
        byte[] buf = getSlice(offset);
        DataIO.putLong(buf, pos, v);
    }


    @Override
    public void putInt(long offset, int value) {
        int pos = (int) (offset & sliceSizeModMask);
        byte[] buf = getSlice(offset);
        buf[pos++] = (byte) (0xff & (value >> 24));
        buf[pos++] = (byte) (0xff & (value >> 16));
        buf[pos++] = (byte) (0xff & (value >> 8));
        buf[pos++] = (byte) (0xff & (value));
    }

    @Override
    public void putByte(long offset, byte value) {
        final byte[] b = getSlice(offset);
        b[((int) (offset & sliceSizeModMask))] = value;
    }

    @Override
    public void putData(long offset, byte[] src, int srcPos, int srcSize) {
        int pos = (int) (offset & sliceSizeModMask);
        byte[] buf = getSlice(offset);
        System.arraycopy(src, srcPos, buf, pos, srcSize);
    }

    @Override
    public void putData(long offset, ByteBuffer buf) {
        int pos = (int) (offset & sliceSizeModMask);
        byte[] dst = getSlice(offset);
        buf.get(dst, pos, buf.remaining());
    }


    @Override
    public void copyTo(long inputOffset, Volume target, long targetOffset, long size) {
        int pos = (int) (inputOffset & sliceSizeModMask);
        byte[] buf = getSlice(inputOffset);

        //TODO size>Integer.MAX_VALUE
        target.putData(targetOffset, buf, pos, (int) size);
    }


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

        if (overlap) {
            while (len > 0) {
                byte[] b = getSlice(offset);
                int pos2 = (int) (offset & sliceSizeModMask);

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

                System.arraycopy(data, pos, b, pos2, 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) {
                byte[] b = getSlice(offset);
                int pos = (int) (offset & sliceSizeModMask);

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

                System.arraycopy(b, pos, bb, origLen - size, toPut);

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

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

        int pos = start;
        while (pos < end) {
            System.arraycopy(CLEAR, 0, buf, pos, Math.min(CLEAR.length, end - pos));
            pos += CLEAR.length;
        }
    }

    @Override
    public long getLong(long offset) {
        int pos = (int) (offset & sliceSizeModMask);
        byte[] buf = getSlice(offset);
        return DataIO.getLong(buf, pos);
    }

    @Override
    public int getInt(long offset) {
        int pos = (int) (offset & sliceSizeModMask);
        byte[] buf = getSlice(offset);

        //TODO verify loop
        final int end = pos + 4;
        int ret = 0;
        for (; pos < end; pos++) {
            ret = (ret << 8) | (buf[pos] & 0xFF);
        }
        return ret;
    }

    @Override
    public byte getByte(long offset) {
        final byte[] b = getSlice(offset);
        return b[((int) (offset & sliceSizeModMask))];
    }

    @Override
    public DataInput2 getDataInput(long offset, int size) {
        int pos = (int) (offset & sliceSizeModMask);
        byte[] buf = getSlice(offset);
        return new DataInput2.ByteArray(buf, pos);
    }

    @Override
    public void getData(long offset, byte[] bytes, int bytesPos, int length) {
        int pos = (int) (offset & sliceSizeModMask);
        byte[] buf = getSlice(offset);
        System.arraycopy(buf, pos, bytes, bytesPos, length);
    }

    @Override
    public void close() {
        closed = true;
        slices = null;
    }

    @Override
    public void sync() {

    }


    @Override
    public int sliceSize() {
        return sliceSize;
    }

    @Override
    public boolean isSliced() {
        return true;
    }

    @Override
    public long length() {
        return ((long) slices.length) * sliceSize;
    }

    @Override
    public boolean isReadOnly() {
        return false;
    }

    @Override
    public File getFile() {
        return null;
    }

    @Override
    public boolean getFileLocked() {
        return false;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy