org.mapdb.volume.ByteBufferVol Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapdb Show documentation
Show all versions of mapdb Show documentation
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.
package org.mapdb.volume;
import org.mapdb.CC;
import org.mapdb.DBException;
import org.mapdb.DataInput2;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
/**
* 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 transferInto(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