| /** |
| * JDBM LICENSE v1.00 |
| * |
| * Redistribution and use of this software and associated documentation |
| * ("Software"), with or without modification, are permitted provided |
| * that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain copyright |
| * statements and notices. Redistributions must also contain a |
| * copy of this document. |
| * |
| * 2. 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. |
| * |
| * 3. The name "JDBM" must not be used to endorse or promote |
| * products derived from this Software without prior written |
| * permission of Cees de Groot. For written permission, |
| * please contact cg@cdegroot.com. |
| * |
| * 4. Products derived from this Software may not be called "JDBM" |
| * nor may "JDBM" appear in their names without prior written |
| * permission of Cees de Groot. |
| * |
| * 5. Due credit should be given to the JDBM Project |
| * (http://jdbm.sourceforge.net/). |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE JDBM PROJECT AND CONTRIBUTORS |
| * ``AS IS'' AND ANY EXPRESSED 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 |
| * CEES DE GROOT OR ANY 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. |
| * |
| * Copyright 2000 (C) Cees de Groot. All Rights Reserved. |
| * Contributions are Copyright (C) 2000 by their associated contributors. |
| * |
| * $Id: BlockIo.java,v 1.2 2002/08/06 05:18:36 boisvert Exp $ |
| */ |
| package jdbm.recman; |
| |
| |
| import java.io.IOException; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| |
| import org.apache.directory.server.i18n.I18n; |
| |
| |
| /** |
| * This class wraps a page-sized byte array and provides methods to read and |
| * write data to and from it. The readers and writers are just the ones that |
| * the rest of the toolkit needs, nothing else. Values written are compatible |
| * with java.io routines. |
| * |
| * This block is never accessed directly, so it does not have to be thread-safe. |
| * |
| * @see java.io.DataInput |
| * @see java.io.DataOutput |
| */ |
| public final class BlockIo implements java.io.Externalizable |
| { |
| public final static long serialVersionUID = 2L; |
| |
| /** The block Identifier */ |
| private long blockId; |
| |
| /** The row data contained in this block */ |
| private transient byte[] data; |
| |
| private transient BlockView view = null; |
| |
| /** A flag set when this block has been modified */ |
| private transient boolean dirty = false; |
| |
| /** The number of pending transaction on this block */ |
| private transient int transactionCount = 0; |
| |
| |
| /** |
| * Default constructor for serialization |
| */ |
| public BlockIo() |
| { |
| // empty |
| } |
| |
| |
| /** |
| * Constructs a new BlockIo instance. |
| * |
| * @param blockId The identifier for this block |
| * @param data The data to store |
| */ |
| BlockIo( long blockId, byte[] data ) |
| { |
| // remove me for production version |
| if ( blockId < 0 ) |
| { |
| throw new Error( I18n.err( I18n.ERR_539_BAD_BLOCK_ID, blockId ) ); |
| } |
| |
| this.blockId = blockId; |
| this.data = data; |
| } |
| |
| |
| /** |
| * @return the underlying array |
| */ |
| byte[] getData() |
| { |
| return data; |
| } |
| |
| |
| /** |
| * Sets the block number. Should only be called by RecordFile. |
| * |
| * @param The block identifier |
| */ |
| void setBlockId( long blockId ) |
| { |
| if ( isInTransaction() ) |
| { |
| throw new Error( I18n.err( I18n.ERR_540 ) ); |
| } |
| |
| if ( blockId < 0 ) |
| { |
| throw new Error( I18n.err( I18n.ERR_539_BAD_BLOCK_ID, blockId ) ); |
| } |
| |
| this.blockId = blockId; |
| } |
| |
| |
| /** |
| * @return the block number. |
| */ |
| long getBlockId() |
| { |
| return blockId; |
| } |
| |
| |
| /** |
| * @return the current view of the block. |
| */ |
| public BlockView getView() |
| { |
| return view; |
| } |
| |
| |
| /** |
| * Sets the current view of the block. |
| */ |
| public void setView( BlockView view ) |
| { |
| this.view = view; |
| } |
| |
| |
| /** |
| * Sets the dirty flag |
| */ |
| void setDirty() |
| { |
| dirty = true; |
| } |
| |
| |
| /** |
| * Clears the dirty flag |
| */ |
| void setClean() |
| { |
| dirty = false; |
| } |
| |
| |
| /** |
| * Returns true if the dirty flag is set. |
| */ |
| boolean isDirty() |
| { |
| return dirty; |
| } |
| |
| |
| /** |
| * Returns true if the block is still dirty with respect to the |
| * transaction log. |
| */ |
| boolean isInTransaction() |
| { |
| return transactionCount != 0; |
| } |
| |
| |
| /** |
| * Increments transaction count for this block, to signal that this |
| * block is in the log but not yet in the data recordFile. The method also |
| * takes a snapshot so that the data may be modified in new transactions. |
| */ |
| synchronized void incrementTransactionCount() |
| { |
| transactionCount++; |
| |
| // @fix me ( alex ) |
| setClean(); |
| } |
| |
| |
| /** |
| * Decrements transaction count for this block, to signal that this |
| * block has been written from the log to the data recordFile. |
| */ |
| synchronized void decrementTransactionCount() |
| { |
| transactionCount--; |
| |
| if ( transactionCount < 0 ) |
| { |
| throw new Error( I18n.err( I18n.ERR_541, getBlockId() ) ); |
| } |
| } |
| |
| |
| /** |
| * Reads a byte from the indicated position |
| */ |
| public byte readByte( int pos ) |
| { |
| return data[pos]; |
| } |
| |
| |
| /** |
| * Writes a byte to the indicated position |
| */ |
| public void writeByte( int pos, byte value ) |
| { |
| data[pos] = value; |
| setDirty(); |
| } |
| |
| |
| /** |
| * Reads a short from the indicated position |
| */ |
| public short readShort( int pos ) |
| { |
| return ( short ) |
| ( ( ( short ) ( data[pos+0] & 0xff ) << 8 ) | |
| ( ( short ) ( data[pos+1] & 0xff ) << 0 ) ); |
| } |
| |
| |
| /** |
| * Writes a short to the indicated position |
| */ |
| public void writeShort( int pos, short value ) |
| { |
| data[pos+0] = ( byte ) ( 0xff & ( value >> 8 ) ); |
| data[pos+1] = ( byte ) ( 0xff & ( value >> 0 ) ); |
| setDirty(); |
| } |
| |
| |
| /** |
| * Reads an int from the indicated position |
| */ |
| public int readInt( int pos ) |
| { |
| return |
| ( ( ( int ) ( data[pos+0] & 0xff ) << 24) | |
| ( ( int ) ( data[pos+1] & 0xff ) << 16) | |
| ( ( int ) ( data[pos+2] & 0xff ) << 8) | |
| ( ( int ) ( data[pos+3] & 0xff ) << 0 ) ); |
| } |
| |
| |
| /** |
| * Writes an int to the indicated position |
| */ |
| public void writeInt( int pos, int value ) |
| { |
| data[pos+0] = ( byte ) ( 0xff & ( value >> 24 ) ); |
| data[pos+1] = ( byte ) ( 0xff & ( value >> 16 ) ); |
| data[pos+2] = ( byte ) ( 0xff & ( value >> 8 ) ); |
| data[pos+3] = ( byte ) ( 0xff & ( value >> 0 ) ); |
| setDirty(); |
| } |
| |
| |
| /** |
| * Reads a long from the indicated position |
| */ |
| public long readLong( int pos ) |
| { |
| // Contributed by Erwin Bolwidt <ejb@klomp.org> |
| // Gives about 15% performance improvement |
| return |
| ( ( long )( ( ( data[pos+0] & 0xff ) << 24 ) | |
| ( ( data[pos+1] & 0xff ) << 16 ) | |
| ( ( data[pos+2] & 0xff ) << 8 ) | |
| ( ( data[pos+3] & 0xff ) ) ) << 32 ) | |
| ( ( long )( ( ( data[pos+4] & 0xff ) << 24 ) | |
| ( ( data[pos+5] & 0xff ) << 16 ) | |
| ( ( data[pos+6] & 0xff ) << 8 ) | |
| ( ( data[pos+7] & 0xff ) ) ) & 0xffffffff ); |
| } |
| |
| |
| /** |
| * Writes a long to the indicated position |
| */ |
| public void writeLong(int pos, long value) { |
| data[pos+0] = (byte)(0xff & (value >> 56)); |
| data[pos+1] = (byte)(0xff & (value >> 48)); |
| data[pos+2] = (byte)(0xff & (value >> 40)); |
| data[pos+3] = (byte)(0xff & (value >> 32)); |
| data[pos+4] = (byte)(0xff & (value >> 24)); |
| data[pos+5] = (byte)(0xff & (value >> 16)); |
| data[pos+6] = (byte)(0xff & (value >> 8)); |
| data[pos+7] = (byte)(0xff & (value >> 0)); |
| setDirty(); |
| } |
| |
| |
| // overrides java.lang.Object |
| |
| public String toString() |
| { |
| return "BlockIO ( " |
| + blockId + ", " |
| + dirty + ", " |
| + view + " )"; |
| } |
| |
| |
| // implement externalizable interface |
| |
| public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException |
| { |
| blockId = in.readLong(); |
| int length = in.readInt(); |
| data = new byte[length]; |
| in.readFully(data); |
| } |
| |
| |
| // implement externalizable interface |
| public void writeExternal( ObjectOutput out ) throws IOException |
| { |
| out.writeLong( blockId ); |
| out.writeInt( data.length ); |
| out.write( data ); |
| } |
| } |