
org.zoodb.jdo.internal.server.StorageReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parent Show documentation
Show all versions of parent Show documentation
ZooDB Java JDO Object Database.
The newest version!
/*
* Copyright 2009-2013 Tilmann Zaeschke. All rights reserved.
*
* This file is part of ZooDB.
*
* ZooDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZooDB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZooDB. If not, see .
*
* See the README and COPYING files for further information.
*/
package org.zoodb.jdo.internal.server;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import org.zoodb.jdo.internal.server.index.BitTools;
import org.zoodb.jdo.internal.util.DBLogger;
public class StorageReader implements StorageChannelInput {
private final ByteBuffer buf;
private int currentPage = -1;
//indicate whether to automatically allocate and move to next page when page end is reached.
private final boolean isAutoPaging;
//The header is only written in auto-paging mode
private long pageHeader = -1;
private final int MAX_POS;
private final StorageChannel root;
private final IntBuffer intBuffer;
private final int[] intArray;
private CallbackPageRead overflowCallback = null;
private DATA_TYPE currentType;
/**
* Use for creating an additional view on a given file.
* @param fc
* @param pageSize
* @param fsm
*/
StorageReader(StorageChannel root, boolean autoPaging) {
this.root = root;
this.MAX_POS = root.getPageSize() - 4;
this.isAutoPaging = autoPaging;
buf = ByteBuffer.allocateDirect(root.getPageSize());
currentPage = -1;
intBuffer = buf.asIntBuffer();
intArray = new int[intBuffer.capacity()];
}
/**
* To be called after every commit, to ensure that pages are reset, in case they have been
* rewritten.
*/
@Override
public void reset() {
currentPage = -1;
}
@Override
public void seekPageForRead(DATA_TYPE type, int pageId) {
seekPage(type, pageId, 0);
}
@Override
public void seekPosAP(DATA_TYPE type, long pageAndOffs) {
int page = BitTools.getPage(pageAndOffs);
int offs = BitTools.getOffs(pageAndOffs);
seekPage(type, page, offs);
}
@Override
public void seekPage(DATA_TYPE type, int pageId, int pageOffset) {
//isAutoPaging = autoPaging;
if (pageId != currentPage) {
currentPage = pageId;
buf.clear();
root.readPage(buf, pageId);
}
currentType = type;
if (type != DATA_TYPE.DB_HEADER) {
buf.clear();
readHeader();
}
if (pageOffset == 0) {
if (isAutoPaging) {
pageOffset = PAGE_HEADER_SIZE_DATA; //TODO this is dirty...
} else {
if (type != DATA_TYPE.DB_HEADER) {
pageOffset = PAGE_HEADER_SIZE;
}
}
}
buf.position(pageOffset);
}
@Override
public String readString() {
checkPosRead(4);
int len = buf.getInt();
//Align for 2-byte writing
int p = buf.position();
if ((p & 0x00000001) == 1) {
buf.position(p+1);
}
char[] array = new char[len];
CharBuffer cb = buf.asCharBuffer();
int l = array.length;
int posA = 0; //position in array
while (l > 0) {
checkPosRead(2);
int getLen = MAX_POS - buf.position();
getLen = getLen >> 1;
if (getLen > l) {
getLen = l;
}
cb = buf.asCharBuffer(); //create a buffer at the correct position
cb.get(array, posA, getLen);
buf.position(buf.position()+getLen*2);
posA += getLen;
l -= getLen;
}
return String.valueOf(array);
//return String.copyValueOf(array);
//return new String(array);
}
@Override
public boolean readBoolean() {
return readByte() != 0;
}
@Override
public byte readByte() {
checkPosRead(S_BYTE);
return buf.get();
}
@Override
public char readChar() {
if (!checkPos(S_CHAR)) {
return readByteBuffer(S_CHAR).getChar();
}
return buf.getChar();
}
@Override
public double readDouble() {
if (!checkPos(S_DOUBLE)) {
return Double.longBitsToDouble(readLong());
}
return buf.getDouble();
}
@Override
public float readFloat() {
if (!checkPos(S_FLOAT)) {
return Float.intBitsToFloat(readInt());
}
return buf.getFloat();
}
@Override
public void readFully(byte[] array) {
int l = array.length;
int posA = 0; //position in array
while (l > 0) {
checkPosRead(1);
int getLen = MAX_POS - buf.position();
if (getLen > l) {
getLen = l;
}
buf.get(array, posA, getLen);
posA += getLen;
l -= getLen;
}
}
@Override
public void noCheckRead(long[] array) {
LongBuffer lb = buf.asLongBuffer();
lb.get(array);
buf.position(buf.position() + S_LONG * array.length);
}
@Override
public void noCheckRead(int[] array) {
IntBuffer lb = buf.asIntBuffer();
lb.get(array);
buf.position(buf.position() + S_INT * array.length);
}
@Override
public void noCheckRead(byte[] array) {
buf.get(array);
}
@Override
public void noCheckReadAsInt(long[] array, int nElements) {
int pos = buf.position();
if ((pos >> 2) << 2 == pos) {
intBuffer.position(pos >> 2);
} else {
intBuffer.position((pos >> 2)+1);
}
intBuffer.get(intArray, 0, nElements);
for (int i = 0; i < nElements; i++) {
array[i] = intArray[i];
}
buf.position(intBuffer.position() * S_INT);
//Alternative implementation (faster according to PerfTest but slower when running JUnit suite
// for (int i = 0; i < nElements; i++) {
// array[i] = buf.getInt();
// }
}
@Override
public int readInt() {
if (!checkPos(S_INT)) {
return readByteBuffer(S_INT).getInt();
}
return buf.getInt();
}
@Override
public long readLong() {
if (!checkPos(S_LONG)) {
return readByteBuffer(S_LONG).getLong();
}
// checkPosRead(S_LONG);
return buf.getLong();
}
@Override
public short readShort() {
if (!checkPos(S_SHORT)) {
return readByteBuffer(S_SHORT).getShort();
}
return buf.getShort();
}
private ByteBuffer readByteBuffer(int len) {
byte[] ba = new byte[len];
readFully(ba);
return ByteBuffer.wrap(ba);
}
@Override
public long getHeaderClassOID() {
return pageHeader;
}
private boolean checkPos(int delta) {
//TODO remove autopaging, the indices use anyway the noCheckMethods!!
//TODO -> otherwise, make it final, as it should be known when a view is constructed.
if (isAutoPaging) {
return (buf.position() + delta - MAX_POS) <= 0;
}
return true;
}
private void checkPosRead(int delta) {
final ByteBuffer buf = this.buf;
if (isAutoPaging && buf.position() + delta > MAX_POS) {
final int pageId = buf.getInt();
currentPage = pageId;
buf.clear();
root.readPage(buf, pageId);
buf.rewind();
//read header
readHeader();
if (overflowCallback != null) {
overflowCallback.notifyOverflowRead(currentPage);
}
}
}
private void readHeader() {
byte pageType = buf.get();
// byte dummy = buf.get();
// short pageVersion = buf.getShort();
// long txId = buf.getLong();
if (pageType != currentType.getId()) {
buf.get(); //dummy
buf.getShort(); //pageVersion
long txId = buf.getLong();
throw DBLogger.newFatal("Page type mismatch, expected " +
currentType.getId() + "/" + currentType + " (tx=" + txId +
") but got " + pageType + " (tx=" + root.getTxId() +
"). PageId=" + currentPage);
}
buf.position(PAGE_HEADER_SIZE);
if (isAutoPaging) {
pageHeader = buf.getLong();
}
}
@Override
public int getOffset() {
return buf.position();
}
@Override
public int getPage() {
return currentPage;
}
@Override
public void skipRead(int nBytes) {
int l = nBytes;
while (l > 0) {
checkPosRead(1);
int bPos = buf.position();
int putLen = MAX_POS - bPos;
if (putLen > l) {
putLen = l;
}
buf.position(bPos + putLen);
l -= putLen;
}
}
@Override
public void setOverflowCallbackRead(CallbackPageRead readCallback) {
if (overflowCallback != null) {
throw new IllegalStateException();
}
overflowCallback = readCallback;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy