blob: bb05994c12291b01a72fbe8b914ee2885482f510 [file] [log] [blame]
/**
* 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 );
}
}