package com.neocoretechs.bigsack.io.pooled; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import com.neocoretechs.bigsack.DBPhysicalConstants; import com.neocoretechs.bigsack.io.IoInterface; /* * Copyright (c) 1997,2003, NeoCoreTechs * All rights reserved. * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * Neither the name of NeoCoreTechs nor the names of its contributors may be * used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * Datablock - Class for doubly linked list DB block (page) * composed of header and data payload whose total size is the constant DBLOCKSIZ * The usual pattern is to have these methods call back through an IoInterface to perform * specific low level record writes. IoInterface is accessed through a request that has been queued * and is being serviced, thus, direct calls back to the file store are appropriate. * Copyright (C) NeoCoreTechs 1997,2014 * @author Groff */ public final class Datablock implements Externalizable { private static boolean DEBUG = false; private long prevblk = -1L; // offset to prev blk in chain private long nextblk = -1L; // offset of next blk in chain private short bytesused; // bytes used this blk-highwater mark private short bytesinuse; // actual # of bytes in use private long pageLSN = -1L; // pageLSN number of this block byte data[]; // data section of blk private boolean incore = false; // is it modified? private boolean inlog = false; // written to log since incore? private static final long serialVersionUID = 1L; // private int datasize; // public Datablock() { this(DBPhysicalConstants.DATASIZE); } public Datablock(int tdatasize) { datasize = tdatasize; data = new byte[datasize]; } /** * Write the header and data portion to IoInterface implementor. * Primarily for freechain create as we used writeUsed otherwise * @param fobj the IoInterface * @exception IOException error writing field */ public synchronized void write(IoInterface fobj) throws IOException { //synchronized(fobj) { fobj.Fwrite_long(getPrevblk()); fobj.Fwrite_long(getNextblk()); fobj.Fwrite_short(getBytesused()); fobj.Fwrite_short(getBytesinuse()); fobj.Fwrite_long(getPageLSN()); fobj.Fwrite(data); //} } /** * write the header and used data portion to IoInterface implementor * @param fobj the IoInterface * @exception IOException error writing field */ public synchronized void writeUsed(IoInterface fobj) throws IOException { //synchronized(fobj) { fobj.Fwrite_long(getPrevblk()); fobj.Fwrite_long(getNextblk()); fobj.Fwrite_short(getBytesused()); fobj.Fwrite_short(getBytesinuse()); fobj.Fwrite_long(getPageLSN()); if (getBytesused() == datasize) fobj.Fwrite(data); else fobj.Fwrite(data, getBytesused()); //} } public synchronized void resetBlock() { if( DEBUG ) System.out.println("Datablock,resetBlock "+this); prevblk = -1L; nextblk = -1L; bytesused = 0; bytesinuse = 0; pageLSN = -1; incore = false; inlog = false; } /** * write the header and data portion to IoInterface implementor * in compressed form * @param fobj the IoInterface * @exception IOException error writing field */ /* protected synchronized void writeCompressed(IoInterface fobj) throws IOException { fobj.Fwrite_long(prevblk); fobj.Fwrite_long(nextblk); fobj.Fwrite_short(bytesused); fobj.Fwrite_short(bytesinuse); fobj.Fwrite_long(pageLSN); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DeflaterOutputStream dfo = new DeflaterOutputStream(baos); dfo.write(data,0,data.length); dfo.close(); baos.close(); byte[] bx = baos.toByteArray(); fobj.Fwrite(bx); } */ /** * read the header and data portion from IoInterface implementor * @param fobj the IoInterface * @exception IOException error reading field */ public synchronized void read(IoInterface fobj) throws IOException { //synchronized(fobj) { setPrevblk(fobj.Fread_long()); setNextblk(fobj.Fread_long()); setBytesused(fobj.Fread_short()); setBytesinuse(fobj.Fread_short()); setPageLSN(fobj.Fread_long()); if (fobj.Fread(data, datasize) != datasize) { throw new IOException( "Datablock read size invalid " + this.toString()); } //} } /** * read the header and used data portion from IoInterface implementor * @param fobj the IoInterface * @exception IOException error reading field */ public synchronized void readUsed(IoInterface fobj) throws IOException { //synchronized(fobj) { setPrevblk(fobj.Fread_long()); setNextblk(fobj.Fread_long()); setBytesused(fobj.Fread_short()); setBytesinuse(fobj.Fread_short()); setPageLSN(fobj.Fread_long()); if (getBytesused() > datasize) { throw new IOException("block inconsistency " + this.toString()); } if (getBytesused() == datasize) { if (fobj.Fread(data) != datasize) { throw new IOException( "Datablock read size invalid " + this.toString()); } } else { if (fobj.Fread(data, getBytesused()) != getBytesused()) { throw new IOException( "Datablock read error bytesused=" + String.valueOf(getBytesused()) + " bytesinuse=" + String.valueOf(getBytesinuse())); } } //} } /** Write this out. @exception IOException error writing to log stream */ public synchronized void writeExternal(ObjectOutput out) throws IOException { out.writeLong(getPrevblk()); out.writeLong(getNextblk()); out.writeShort(getBytesused()); out.writeShort(getBytesinuse()); out.writeLong(getPageLSN()); if (getBytesused() == datasize) out.write(data); else out.write(data, 0, getBytesused()); } /** Read this in @exception IOException error reading from log stream @exception ClassNotFoundException corrupted log stream */ public synchronized void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { setPrevblk(in.readLong()); setNextblk(in.readLong()); setBytesused(in.readShort()); setBytesinuse(in.readShort()); setPageLSN(in.readLong()); in.read(data); //if (in.read(data) != datasize) { // throw new IOException( // "Datablock read size invalid " + this.toString()); //} } /** for debugging, write block info */ public synchronized String blockdump() { int nzero=0; for(int i =0;i<datasize;i++) { if(data[i] != 0) { ++nzero; } } return "Blockdump "+this.toString()+" "+(nzero == 0 ? "NO Non-Zero elements found" : nzero+" non-zero elements found"); } /** * deep copy * @return The clone of this block */ synchronized Datablock doClone() { Datablock d = new Datablock(DBPhysicalConstants.DATASIZE); d.setPrevblk(prevblk); d.setNextblk(nextblk); d.setBytesused(bytesused); d.setBytesinuse(bytesinuse); System.arraycopy(data, 0, d.data, 0, getBytesused()); d.setIncore(true); return d; } /** * deep copy * @param d The block whose values are set from 'this' instance */ public synchronized void doClone(Datablock d) { d.setPrevblk(prevblk); d.setNextblk(nextblk); d.setBytesused(bytesused); d.setBytesinuse(bytesinuse); d.setPageLSN(pageLSN); System.arraycopy(data, 0, d.data, 0, getBytesused()); d.setIncore(incore); d.setInlog(inlog); } public synchronized String toString() { //String o = new String("Elems all 0"); //for(int i =0;i<datasize;i++) { // if(data[i] != 0) { // o = new String("Some elems not 0"); // break; // } //} o+= //String o = return "DBLK: prev = " + prevblk + " next = " + nextblk + " bytesused = " + bytesused + " bytesinuse = " + bytesinuse + " pageLSN: " + pageLSN + " incore " + incore; //return o; } public synchronized short getBytesinuse() { return bytesinuse; } public synchronized void setBytesinuse(short bytesinuse) { this.bytesinuse = bytesinuse; } public synchronized String toBriefString() { return ( prevblk !=-1 || nextblk !=-1 || bytesused != 0 || bytesinuse != 0 || pageLSN != -1 || incore) ? "DBLK prev = " + GlobalDBIO.valueOf(getPrevblk()) + " next = " + GlobalDBIO.valueOf(getNextblk()) + " bytesused = " + bytesused + " bytesinuse = " + bytesinuse + " pageLSN: " + pageLSN + " incore " + incore : "[[ Block Empty ]]"; } public synchronized boolean isIncore() { return incore; } public synchronized void setIncore(boolean incore) { this.incore = incore; } public synchronized long getPrevblk() { return prevblk; } public synchronized void setPrevblk(long prevblk) { this.prevblk = prevblk; } public synchronized long getNextblk() { return nextblk; } public synchronized void setNextblk(long nextblk) { this.nextblk = nextblk; } public synchronized short getBytesused() { return bytesused; } public synchronized void setBytesused(short bytesused) { this.bytesused = bytesused; } public synchronized long getPageLSN() { return pageLSN; } public synchronized void setPageLSN(long version) { this.pageLSN = version; } public synchronized boolean isInlog() { return inlog; } public synchronized void setInlog(boolean inlog) { this.inlog = inlog; } public synchronized byte[] getData() { return data; } }