Author: elecharny Date: Thu Aug 25 18:09:19 2011 New Revision: 1161673 URL: http://svn.apache.org/viewvc?rev=1161673&view=rev Log: added many Javadoc and comments. Refactored some parts of the code Added: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockView.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FileHeader.java directory/apacheds/trunk/jdbm/src/test/java/jdbm/recman/BlockIoTest.java Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockIo.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/DataPage.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Location.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageHeader.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageManager.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PhysicalRowIdManager.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Provider.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/RecordFile.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TransactionManager.java directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TranslationPage.java directory/apacheds/trunk/jdbm/src/test/java/jdbm/btree/StreamCorrupted.java Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java Thu Aug 25 18:09:19 2011 @@ -49,15 +49,14 @@ package jdbm.recman; import java.io.IOException; - import java.util.HashMap; import java.util.Map; -import org.apache.directory.server.i18n.I18n; - import jdbm.RecordManager; -import jdbm.helper.Serializer; import jdbm.helper.DefaultSerializer; +import jdbm.helper.Serializer; + +import org.apache.directory.server.i18n.I18n; /** * This class manages records, which are uninterpreted blobs of data. The @@ -84,7 +83,6 @@ import jdbm.helper.DefaultSerializer; public final class BaseRecordManager implements RecordManager { - /** Underlying record recordFile. */ private RecordFile recordFile; @@ -326,6 +324,7 @@ public final class BaseRecordManager { System.out.println( "BaseRecordManager.fetch() recid " + recid + " length " + data.length ) ; } + return serializer.deserialize( data ); } Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockIo.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockIo.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockIo.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockIo.java Thu Aug 25 18:09:19 2011 @@ -50,6 +50,8 @@ package jdbm.recman; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; +import java.util.concurrent.atomic.AtomicInteger; + import org.apache.directory.server.i18n.I18n; @@ -73,15 +75,16 @@ public final class BlockIo implements ja private long blockId; /** The row data contained in this block */ - private transient byte[] data; + private byte[] data; - private transient BlockView view = null; + /** A view on the BlockIo */ + private BlockView view = null; /** A flag set when this block has been modified */ - private transient boolean dirty = false; + private boolean dirty = false; /** The number of pending transaction on this block */ - private transient int transactionCount = 0; + private AtomicInteger transactionCount = new AtomicInteger( 0 ); /** @@ -99,7 +102,7 @@ public final class BlockIo implements ja * @param blockId The identifier for this block * @param data The data to store */ - BlockIo( long blockId, byte[] data ) + /*No qualifier*/ BlockIo( long blockId, byte[] data ) { // remove me for production version if ( blockId < 0 ) @@ -115,7 +118,7 @@ public final class BlockIo implements ja /** * @return the underlying array */ - byte[] getData() + /*No qualifier*/ byte[] getData() { return data; } @@ -126,7 +129,7 @@ public final class BlockIo implements ja * * @param The block identifier */ - void setBlockId( long blockId ) + /*No qualifier*/ void setBlockId( long blockId ) { if ( isInTransaction() ) { @@ -145,7 +148,7 @@ public final class BlockIo implements ja /** * @return the block number. */ - long getBlockId() + /*No qualifier*/ long getBlockId() { return blockId; } @@ -162,6 +165,8 @@ public final class BlockIo implements ja /** * Sets the current view of the block. + * + * @param view the current view */ public void setView( BlockView view ) { @@ -172,7 +177,7 @@ public final class BlockIo implements ja /** * Sets the dirty flag */ - void setDirty() + /*No qualifier*/ void setDirty() { dirty = true; } @@ -181,7 +186,7 @@ public final class BlockIo implements ja /** * Clears the dirty flag */ - void setClean() + /*No qualifier*/ void setClean() { dirty = false; } @@ -190,7 +195,7 @@ public final class BlockIo implements ja /** * Returns true if the dirty flag is set. */ - boolean isDirty() + /*No qualifier*/ boolean isDirty() { return dirty; } @@ -200,9 +205,9 @@ public final class BlockIo implements ja * Returns true if the block is still dirty with respect to the * transaction log. */ - boolean isInTransaction() + /*No qualifier*/ boolean isInTransaction() { - return transactionCount != 0; + return transactionCount.get() != 0; } @@ -211,12 +216,9 @@ public final class BlockIo implements ja * 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() + /*No qualifier*/ void incrementTransactionCount() { - transactionCount++; - - // @fix me ( alex ) - setClean(); + transactionCount.getAndIncrement(); } @@ -224,11 +226,9 @@ public final class BlockIo implements ja * Decrements transaction count for this block, to signal that this * block has been written from the log to the data recordFile. */ - synchronized void decrementTransactionCount() + /*No qualifier*/ void decrementTransactionCount() { - transactionCount--; - - if ( transactionCount < 0 ) + if ( transactionCount.decrementAndGet() < 0 ) { throw new Error( I18n.err( I18n.ERR_541, getBlockId() ) ); } @@ -237,6 +237,9 @@ public final class BlockIo implements ja /** * Reads a byte from the indicated position + * + * @param pos the position at which we will read the byte + * @return the read byte */ public byte readByte( int pos ) { @@ -246,51 +249,66 @@ public final class BlockIo implements ja /** * Writes a byte to the indicated position + * + * @param pos The position where we want to write the value to + * @param value the byte value we want to write into the BlockIo */ public void writeByte( int pos, byte value ) { data[pos] = value; - setDirty(); + dirty = true; } /** * Reads a short from the indicated position + * + * @param pos the position at which we will read the short + * @return the read short */ public short readShort( int pos ) { return ( short ) - ( ( ( short ) ( data[pos+0] & 0xff ) << 8 ) | - ( ( short ) ( data[pos+1] & 0xff ) << 0 ) ); + ( ( ( data[pos+0] & 0xff ) << 8 ) | + ( ( data[pos+1] & 0xff ) << 0 ) ); } /** * Writes a short to the indicated position + * + * @param pos The position where we want to write the value to + * @param value the short value we want to write into the BlockIo */ public void writeShort( int pos, short value ) { data[pos+0] = ( byte ) ( 0xff & ( value >> 8 ) ); data[pos+1] = ( byte ) ( 0xff & ( value >> 0 ) ); - setDirty(); + dirty = true; } /** * Reads an int from the indicated position + * + * @param pos the position at which we will read the int + * @return the read int */ 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 ) ); + ( data[pos+0] << 24) | + ( ( data[pos+1] & 0xff ) << 16) | + ( ( data[pos+2] & 0xff ) << 8) | + ( ( data[pos+3] & 0xff ) << 0 ); } /** * Writes an int to the indicated position + * + * @param pos The position where we want to write the value to + * @param value the int value we want to write into the BlockIo */ public void writeInt( int pos, int value ) { @@ -298,31 +316,35 @@ public final class BlockIo implements ja data[pos+1] = ( byte ) ( 0xff & ( value >> 16 ) ); data[pos+2] = ( byte ) ( 0xff & ( value >> 8 ) ); data[pos+3] = ( byte ) ( 0xff & ( value >> 0 ) ); - setDirty(); + dirty = true; } /** * Reads a long from the indicated position + * + * @param pos the position at which we will read the long + * @return the read long */ public long readLong( int pos ) { - // Contributed by Erwin Bolwidt - // 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 ); + ( ( long )( (long)data[pos+0] << 56 ) | + ( (long)( data[pos+1] & 0xff ) << 48 ) | + ( (long)( data[pos+2] & 0xff ) << 40 ) | + ( (long)( data[pos+3] & 0xff ) << 32 ) | + ( (long)( data[pos+4] & 0xff ) << 24 ) | + ( (long)( data[pos+5] & 0xff ) << 16 ) | + ( (long)( data[pos+6] & 0xff ) << 8 ) | + ( (long)( data[pos+7] & 0xff ) ) ); } /** * Writes a long to the indicated position + * + * @param pos The position where we want to write the value to + * @param value the long value we want to write into the BlockIo */ public void writeLong(int pos, long value) { data[pos+0] = (byte)(0xff & (value >> 56)); @@ -333,12 +355,13 @@ public final class BlockIo implements ja data[pos+5] = (byte)(0xff & (value >> 16)); data[pos+6] = (byte)(0xff & (value >> 8)); data[pos+7] = (byte)(0xff & (value >> 0)); - setDirty(); + dirty = true; } - // overrides java.lang.Object - + /** + * {@inheritDoc} + */ public String toString() { return "BlockIO ( " @@ -348,8 +371,9 @@ public final class BlockIo implements ja } - // implement externalizable interface - + /** + * implement externalizable interface + */ public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { blockId = in.readLong(); @@ -359,7 +383,9 @@ public final class BlockIo implements ja } - // implement externalizable interface + /** + * implement externalizable interface + */ public void writeExternal( ObjectOutput out ) throws IOException { out.writeLong( blockId ); Added: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockView.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockView.java?rev=1161673&view=auto ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockView.java (added) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/BlockView.java Thu Aug 25 18:09:19 2011 @@ -0,0 +1,59 @@ +/** + * 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: BlockView.java,v 1.2 2005/06/25 23:12:32 doomdark Exp $ + */ +package jdbm.recman; + + + +/** + * This is a marker interface that is implemented by classes that + * interpret blocks of data by pretending to be an overlay. + * + * @see BlockIo#setView + */ +public interface BlockView +{ +} Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/DataPage.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/DataPage.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/DataPage.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/DataPage.java Thu Aug 25 18:09:19 2011 @@ -47,6 +47,7 @@ package jdbm.recman; + import org.apache.directory.server.i18n.I18n; @@ -56,14 +57,13 @@ import org.apache.directory.server.i18n. final class DataPage extends PageHeader { // offsets - /** first short in the file after the page header info: 18 byte offset */ private static final short O_FIRST = PageHeader.SIZE; // short firstrowid /** start of the data in this block: 20 byte offset */ static final short O_DATA = ( short ) ( O_FIRST + Magic.SZ_SHORT ); - /** total amount of data in this page/block: 8172 bytes */ + /** total amount of data in this page/block: BLOCK_SIZE - 20 bytes */ static final short DATA_PER_PAGE = ( short ) ( RecordFile.BLOCK_SIZE - O_DATA ); @@ -79,28 +79,33 @@ final class DataPage extends PageHeader /** * Factory method to create or return a data page for the indicated block. */ - static DataPage getDataPageView( BlockIo block ) + static DataPage getDataPageView( BlockIo blockIo ) { - BlockView view = block.getView(); - if ( view != null && view instanceof DataPage ) + BlockView view = blockIo.getView(); + + if ( ( view != null ) && ( view instanceof DataPage ) ) { return ( DataPage ) view; } else { - return new DataPage( block ); + return new DataPage( blockIo ); } } - /** Returns the first rowid's offset */ + /** + * @return the first rowid's offset + */ short getFirst() { return block.readShort( O_FIRST ); } - /** Sets the first rowid's offset */ + /** + * Sets the first rowid's offset + */ void setFirst( short value ) { paranoiaMagicOk(); Added: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FileHeader.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FileHeader.java?rev=1161673&view=auto ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FileHeader.java (added) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FileHeader.java Thu Aug 25 18:09:19 2011 @@ -0,0 +1,205 @@ +/** + * 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: FileHeader.java,v 1.3 2005/06/25 23:12:32 doomdark Exp $ + */ +package jdbm.recman; + + +import java.io.IOException; + +import org.apache.directory.server.i18n.I18n; + + +/** + * This class represents a file header. It is a 1:1 representation of + * the data that appears in block 0 of a file.
+ * The FileHeader is stored into a BlockIo.
+ * The BlockIo will always contain the following bytes :
+ * + */ +class FileHeader implements BlockView +{ + /** Position of the Magic number for FileHeader */ + private static final short O_MAGIC = 0; // short magic + + /** Position of the Lists in the blockIo */ + private static final short O_LISTS = Magic.SZ_SHORT; // long[2*NLISTS] + + /** Position of the ROOTs in the blockIo */ + private static final int O_ROOTS = O_LISTS + ( Magic.NLISTS * 2 * Magic.SZ_LONG ); + + /** The BlockIo used to store the FileHeader */ + private BlockIo block; + + /** The number of "root" rowids available in the file. */ + static final int NROOTS = ( RecordFile.BLOCK_SIZE - O_ROOTS ) / Magic.SZ_LONG; + + + /** + * Constructs a FileHeader object from a block. + * + * @param block The block that contains the file header + * @param isNew If true, the file header is for a new file. + * @throws IOException if the block is too short to keep the file + * header. + */ + FileHeader( BlockIo block, boolean isNew ) + { + this.block = block; + + if ( isNew ) + { + block.writeShort( O_MAGIC, Magic.FILE_HEADER ); + } + else if ( block.readShort( O_MAGIC ) != Magic.FILE_HEADER ) + { + throw new Error( I18n.err( I18n.ERR_544, block.readShort( O_MAGIC ) ) ); + } + } + + + /** + * Returns the offset of the "first" block of the indicated list + */ + private short offsetOfFirst( int list ) + { + return ( short ) ( O_LISTS + ( 2 * Magic.SZ_LONG * list ) ); + } + + + /** + * Returns the offset of the "last" block of the indicated list + */ + private short offsetOfLast( int list ) + { + return ( short ) ( offsetOfFirst( list ) + Magic.SZ_LONG ); + } + + + /** + * Returns the offset of the indicated root + */ + private short offsetOfRoot( int root ) + { + return ( short ) ( O_ROOTS + ( root * Magic.SZ_LONG ) ); + } + + + /** + * Returns the first block of the indicated list + */ + long getFirstOf( int list ) + { + return block.readLong( offsetOfFirst( list ) ); + } + + + /** + * Sets the first block of the indicated list + */ + void setFirstOf( int list, long value ) + { + block.writeLong( offsetOfFirst( list ), value ); + } + + + /** + * Returns the last block of the indicated list + */ + long getLastOf( int list ) + { + return block.readLong( offsetOfLast( list ) ); + } + + + /** + * Sets the last block of the indicated list + */ + void setLastOf( int list, long value ) + { + block.writeLong( offsetOfLast( list ), value ); + } + + + /** + * Returns the indicated root rowid. A root rowid is a special rowid + * that needs to be kept between sessions. It could conceivably be + * stored in a special file, but as a large amount of space in the + * block header is wasted anyway, it's more useful to store it where + * it belongs. + * + * @see #NROOTS + */ + long getRoot( int root ) + { + return block.readLong( offsetOfRoot( root ) ); + } + + + /** + * Sets the indicated root rowid. + * + * @see #getRoot + * @see #NROOTS + */ + void setRoot( int root, long rowid ) + { + block.writeLong( offsetOfRoot( root ), rowid ); + } +} Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java Thu Aug 25 18:09:19 2011 @@ -47,6 +47,7 @@ package jdbm.recman; + /** * Class describing a page that holds logical rowids that were freed. Note * that the methods have *physical* rowids in their signatures - this is @@ -55,9 +56,13 @@ package jdbm.recman; */ class FreeLogicalRowIdPage extends PageHeader { - // offsets + /** The offset for the number of free pages */ private static final short O_COUNT = PageHeader.SIZE; // short count + + /** */ static final short O_FREE = O_COUNT + Magic.SZ_SHORT; + + /** */ static final short ELEMS_PER_PAGE = ( RecordFile.BLOCK_SIZE - O_FREE ) / PhysicalRowId.SIZE; // slots we returned. @@ -79,83 +84,128 @@ class FreeLogicalRowIdPage extends PageH static FreeLogicalRowIdPage getFreeLogicalRowIdPageView( BlockIo block ) { BlockView view = block.getView(); + if ( view != null && view instanceof FreeLogicalRowIdPage ) { return ( FreeLogicalRowIdPage ) view; } else { - return new FreeLogicalRowIdPage(block); + return new FreeLogicalRowIdPage( block ); } } - /** Returns the number of free rowids */ - short getCount() { - return block.readShort(O_COUNT); + /** + * @return the number of free rowids + */ + short getCount() + { + return block.readShort( O_COUNT ); } + - /** Sets the number of free rowids */ - private void setCount(short i) { + /** + * Sets the number of free rowids + */ + private void setCount(short i) + { block.writeShort(O_COUNT, i); } + - /** Frees a slot */ - void free(int slot) { + /** + * Frees a slot + */ + void free(int slot) + { get(slot).setBlock(0); setCount((short) (getCount() - 1)); } + - /** Allocates a slot */ - PhysicalRowId alloc(int slot) { + /** + * Allocates a slot + */ + PhysicalRowId alloc(int slot) + { setCount((short) (getCount() + 1)); get(slot).setBlock(-1); return get(slot); } + - /** Returns true if a slot is allocated */ - boolean isAllocated(int slot) { + /** + * Returns true if a slot is allocated + */ + boolean isAllocated(int slot) + { return get(slot).getBlock() > 0; } + - /** Returns true if a slot is free */ - boolean isFree(int slot) { + /** + * Returns true if a slot is free + */ + boolean isFree(int slot) + { return !isAllocated(slot); } - /** Returns the value of the indicated slot */ - PhysicalRowId get(int slot) { + /** + * Returns the value of the indicated slot + */ + PhysicalRowId get(int slot) + { if (slots[slot] == null) + { slots[slot] = new PhysicalRowId(block, slotToOffset(slot)); + } + return slots[slot]; } + - /** Converts slot to offset */ - private short slotToOffset(int slot) { - return (short) (O_FREE + - (slot * PhysicalRowId.SIZE)); + /** + * Converts slot to offset + */ + private short slotToOffset(int slot) + { + return (short) (O_FREE + (slot * PhysicalRowId.SIZE)); } + /** * Returns first free slot, -1 if no slots are available */ - int getFirstFree() { - for (int i = 0; i < ELEMS_PER_PAGE; i++) { + int getFirstFree() + { + for (int i = 0; i < ELEMS_PER_PAGE; i++) + { if (isFree(i)) + { return i; + } } + return -1; } + /** * Returns first allocated slot, -1 if no slots are available. */ - int getFirstAllocated() { - for (int i = 0; i < ELEMS_PER_PAGE; i++) { + int getFirstAllocated() + { + for (int i = 0; i < ELEMS_PER_PAGE; i++) + { if (isAllocated(i)) + { return i; + } } + return -1; } } Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java Thu Aug 25 18:09:19 2011 @@ -53,7 +53,8 @@ import java.io.IOException; * This class manages free Logical rowid pages and provides methods * to free and allocate Logical rowids on a high level. */ -final class FreeLogicalRowIdPageManager { +final class FreeLogicalRowIdPageManager +{ // our record recordFile private RecordFile recordFile; // our page manager @@ -63,78 +64,94 @@ final class FreeLogicalRowIdPageManager * Creates a new instance using the indicated record file and * page manager. */ - FreeLogicalRowIdPageManager( PageManager pageManager) throws IOException { + FreeLogicalRowIdPageManager( PageManager pageManager) throws IOException + { this.pageManager = pageManager; this.recordFile = pageManager.getRecordFile(); } + /** - * Returns a free Logical rowid, or - * null if nothing was found. + * Returns a free Logical rowid, or null if nothing was found. */ - Location get() throws IOException { - + Location get() throws IOException + { // Loop through the free Logical rowid list until we find // the first rowid. Location retval = null; PageCursor curs = new PageCursor(pageManager, Magic.FREELOGIDS_PAGE); - while (curs.next() != 0) { + + while (curs.next() != 0) + { FreeLogicalRowIdPage fp = FreeLogicalRowIdPage - .getFreeLogicalRowIdPageView(recordFile.get(curs.getCurrent())); + .getFreeLogicalRowIdPageView( recordFile.get( curs.getCurrent() ) ); int slot = fp.getFirstAllocated(); - if (slot != -1) { + + if ( slot != -1 ) + { // got one! - retval = - new Location(fp.get(slot)); + retval = new Location( fp.get( slot ) ); fp.free(slot); - if (fp.getCount() == 0) { + + if ( fp.getCount() == 0 ) + { // page became empty - free it recordFile.release(curs.getCurrent(), false); pageManager.free(Magic.FREELOGIDS_PAGE, curs.getCurrent()); } else + { recordFile.release(curs.getCurrent(), true); + } return retval; } - else { + else + { // no luck, go to next page recordFile.release(curs.getCurrent(), false); } } + return null; } + /** * Puts the indicated rowid on the free list */ - void put(Location rowid) - throws IOException { + void put(Location rowid) throws IOException + { PhysicalRowId free = null; PageCursor curs = new PageCursor(pageManager, Magic.FREELOGIDS_PAGE); long freePage = 0; - while (curs.next() != 0) { + + while (curs.next() != 0) + { freePage = curs.getCurrent(); BlockIo curBlock = recordFile.get(freePage); - FreeLogicalRowIdPage fp = FreeLogicalRowIdPage - .getFreeLogicalRowIdPageView(curBlock); + FreeLogicalRowIdPage fp = FreeLogicalRowIdPage.getFreeLogicalRowIdPageView(curBlock); int slot = fp.getFirstFree(); - if (slot != -1) { + + if ( slot != -1 ) + { free = fp.alloc(slot); break; } recordFile.release(curBlock); } - if (free == null) { + + if (free == null) + { // No more space on the free list, add a page. freePage = pageManager.allocate(Magic.FREELOGIDS_PAGE); BlockIo curBlock = recordFile.get(freePage); - FreeLogicalRowIdPage fp = - FreeLogicalRowIdPage.getFreeLogicalRowIdPageView(curBlock); + FreeLogicalRowIdPage fp = FreeLogicalRowIdPage.getFreeLogicalRowIdPageView(curBlock); free = fp.alloc(0); } + free.setBlock(rowid.getBlock()); free.setOffset(rowid.getOffset()); recordFile.release(freePage, true); Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java Thu Aug 25 18:09:19 2011 @@ -47,6 +47,7 @@ package jdbm.recman; + /** * Class describing a page that holds physical rowids that were freed. */ @@ -76,6 +77,7 @@ final class FreePhysicalRowIdPage extend static FreePhysicalRowIdPage getFreePhysicalRowIdPageView( BlockIo block ) { BlockView view = block.getView(); + if ( view != null && view instanceof FreePhysicalRowIdPage ) { return ( FreePhysicalRowIdPage ) view; @@ -87,21 +89,27 @@ final class FreePhysicalRowIdPage extend } - /** Returns the number of free rowids */ + /** + * Returns the number of free rowids + */ short getCount() { return block.readShort( O_COUNT ); } - /** Sets the number of free rowids */ + /** + * Sets the number of free rowids + */ private void setCount( short i ) { block.writeShort( O_COUNT, i ); } - /** Frees a slot */ + /** + * Frees a slot + */ void free( int slot ) { get( slot ).setSize( 0 ); @@ -109,7 +117,9 @@ final class FreePhysicalRowIdPage extend } - /** Allocates a slot */ + /** + * Allocates a slot + */ FreePhysicalRowId alloc( int slot ) { setCount( ( short ) ( getCount() + 1 ) ); @@ -117,21 +127,27 @@ final class FreePhysicalRowIdPage extend } - /** Returns true if a slot is allocated */ + /** + * Returns true if a slot is allocated + */ boolean isAllocated( int slot ) { return get( slot ).getSize() != 0; } - /** Returns true if a slot is free */ + /** + * Returns true if a slot is free + */ boolean isFree( int slot ) { return ! isAllocated( slot ); } - /** Returns the value of the indicated slot */ + /** + * Returns the value of the indicated slot + */ FreePhysicalRowId get( int slot ) { if ( slots[slot] == null ) @@ -143,7 +159,9 @@ final class FreePhysicalRowIdPage extend } - /** Converts slot to offset */ + /** + * Converts slot to offset + */ short slotToOffset( int slot ) { return ( short ) ( O_FREE + ( slot * FreePhysicalRowId.SIZE ) ); @@ -151,7 +169,7 @@ final class FreePhysicalRowIdPage extend /** - * Returns first free slot, -1 if no slots are available + * @return first free slot, -1 if no slots are available */ int getFirstFree() { @@ -168,7 +186,7 @@ final class FreePhysicalRowIdPage extend /** - * Returns first slot with available size >= indicated size, or -1 if no + * @return first slot with available size >= indicated size, or -1 if no * slots are available. */ int getFirstLargerThan( int size ) Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Location.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Location.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Location.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Location.java Thu Aug 25 18:09:19 2011 @@ -54,7 +54,10 @@ package jdbm.recman; */ final class Location { + /** The block in which the data is stored */ private long block; + + /** The offset within this block */ private short offset; Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java Thu Aug 25 18:09:19 2011 @@ -142,8 +142,8 @@ final class LogicalRowIdManager */ Location fetch( Location rowid ) throws IOException { - TranslationPage xlatPage = TranslationPage.getTranslationPageView( recordFile.get( rowid.getBlock() ) ); + try { Location retval = new Location( xlatPage.get( rowid.getOffset() ) ); Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageHeader.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageHeader.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageHeader.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageHeader.java Thu Aug 25 18:09:19 2011 @@ -47,6 +47,8 @@ package jdbm.recman; +import java.io.IOException; + import org.apache.directory.server.i18n.I18n; @@ -58,6 +60,7 @@ import org.apache.directory.server.i18n. *
  • 2 bytes: the short block type code
  • *
  • 8 bytes: the long block id of the next block in the block list
  • *
  • 8 bytes: the long block id of the previous block in the block list
  • + *
  • 4 bytes: the size of this page * * * The page header block view hence sees 18 bytes of page header data. @@ -65,15 +68,16 @@ import org.apache.directory.server.i18n. public class PageHeader implements BlockView { // offsets into page header's (BlockIo's) buffer - /** the page (BlockIo's type code) short magic code */ private static final short O_MAGIC = 0; + /** the long block id of the next block in the block list */ private static final short O_NEXT = Magic.SZ_SHORT; + /** the long block id of the previous block in the block list */ private static final short O_PREV = O_NEXT + Magic.SZ_LONG; - /** the size of this page header = 18 bytes */ + /** the size of this page header */ protected static final short SIZE = O_PREV + Magic.SZ_LONG; /** the page header block this view is associated with */ @@ -90,6 +94,7 @@ public class PageHeader implements Block { this.block = block; block.setView( this ); + if ( ! magicOk() ) { throw new Error( I18n.err( I18n.ERR_546, block.getBlockId(), getMagic() ) ); @@ -115,6 +120,7 @@ public class PageHeader implements Block static PageHeader getView ( BlockIo block ) { BlockView view = block.getView(); + if ( view != null && view instanceof PageHeader ) { return ( PageHeader ) view; @@ -132,6 +138,7 @@ public class PageHeader implements Block private boolean magicOk() { int magic = getMagic(); + return magic >= Magic.BLOCK && magic <= ( Magic.BLOCK + Magic.FREEPHYSIDS_PAGE ); } @@ -149,22 +156,31 @@ public class PageHeader implements Block } - /** Returns the magic code */ + /** + * @return The magic code (ie, the 2 first bytes of the inner BlockIo) + */ short getMagic() { return block.readShort( O_MAGIC ); } - /** Returns the next block. */ + /** + * @return the next block (ie the long at position 2 in the BlockIo) + */ long getNext() { paranoiaMagicOk(); + return block.readLong( O_NEXT ); } - /** Sets the next block. */ + /** + * Sets the next block. + * + * @param The next Block ID + */ void setNext( long next ) { paranoiaMagicOk(); @@ -172,15 +188,20 @@ public class PageHeader implements Block } - /** Returns the previous block. */ + /** + * @return the previous block (ie the long at position 10 in the BlockIo) + */ long getPrev() { paranoiaMagicOk(); + return block.readLong( O_PREV ); } - /** Sets the previous block. */ + /** + * Sets the previous block. + */ void setPrev( long prev ) { paranoiaMagicOk(); @@ -188,8 +209,12 @@ public class PageHeader implements Block } - /** Sets the type of the page header */ - void setType ( short type ) + /** + * Sets the type of the page header + * + * @param type The PageHeader type to store at position 0 + */ + void setType( short type ) { block.writeShort( O_MAGIC, ( short ) ( Magic.BLOCK + type ) ); } Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageManager.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageManager.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PageManager.java Thu Aug 25 18:09:19 2011 @@ -47,28 +47,34 @@ package jdbm.recman; -import java.io.*; +import java.io.IOException; import org.apache.directory.server.i18n.I18n; /** - * This class manages the linked lists of pages that make up a recordFile. + * This class manages the linked lists of pages that make up a recordFile. It contains + * a FileHeadrer and a reference to the recordFile it manages.
    */ final class PageManager { - // our record recordFile + /** our record recordFile */ private RecordFile recordFile; - // header data + /** header data */ private FileHeader header; - // recordFile header containing block + /** recordFile header containing block */ private BlockIo headerBuf; /** * Creates a new page manager using the indicated record recordFile. + * We will load in memory the associated FileHeader, which is + * read from the RecordFile if it exists, or is created if it doesn't. + * + * @param The associated RecordFile + * @throws IOException If there is an issue storing data into the recordFile */ PageManager( RecordFile recordFile ) throws IOException { @@ -78,54 +84,54 @@ final class PageManager headerBuf = recordFile.get( 0 ); // Assume recordFile is new if the recordFile header's magic number is 0. - if ( headerBuf.readShort( 0 ) == 0 ) - { - header = new FileHeader( headerBuf, true ); - } - else // header is for existing recordFile - { - header = new FileHeader( headerBuf, false ); - } + boolean isNew = headerBuf.readShort( 0 ) == 0; + + header = new FileHeader( headerBuf, isNew ); } /** - * Allocates a page of the indicated type. Returns recid of the page. + * Allocates a page of the indicated type. + * + * @param The page type we want to allocate + * @return The record ID of the page. */ long allocate( short type ) throws IOException { if ( type == Magic.FREE_PAGE ) { + // We can't allocate FREE page. A page becomes FREE after it ha sbeen used. throw new Error( I18n.err( I18n.ERR_548 ) ); } boolean isNew = false; // Do we have something on the free list? - long retval = header.getFirstOf( Magic.FREE_PAGE ); - if ( retval != 0 ) + long freeBlock = header.getFirstOf( Magic.FREE_PAGE ); + + if ( freeBlock != 0 ) { // yes. Point to it and make the next of that page the // new first free page. - header.setFirstOf( Magic.FREE_PAGE, getNext( retval ) ); + header.setFirstOf( Magic.FREE_PAGE, getNext( freeBlock ) ); } else { // nope. make a new record - retval = header.getLastOf( Magic.FREE_PAGE ); + freeBlock = header.getLastOf( Magic.FREE_PAGE ); - if ( retval == 0 ) + if ( freeBlock == 0 ) { // very new recordFile - allocate record #1 - retval = 1; + freeBlock = 1; } - header.setLastOf( Magic.FREE_PAGE, retval + 1 ); + header.setLastOf( Magic.FREE_PAGE, freeBlock + 1 ); isNew = true; } // Cool. We have a record, add it to the correct list - BlockIo buf = recordFile.get( retval ); + BlockIo buf = recordFile.get( freeBlock ); PageHeader pageHdr = null; if ( isNew ) @@ -148,25 +154,25 @@ final class PageManager if ( oldLast == 0 ) { // This was the first one of this type - header.setFirstOf( type, retval ); + header.setFirstOf( type, freeBlock ); } - header.setLastOf( type, retval ); - recordFile.release( retval, true ); + header.setLastOf( type, freeBlock ); + recordFile.release( freeBlock, true ); // If there's a previous, fix up its pointer if ( oldLast != 0 ) { buf = recordFile.get( oldLast ); pageHdr = PageHeader.getView( buf ); - pageHdr.setNext( retval ); + pageHdr.setNext( freeBlock ); recordFile.release( oldLast, true ); } // remove the view, we have modified the type. buf.setView( null ); - return retval; + return freeBlock; } Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PhysicalRowIdManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PhysicalRowIdManager.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PhysicalRowIdManager.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/PhysicalRowIdManager.java Thu Aug 25 18:09:19 2011 @@ -80,6 +80,7 @@ final class PhysicalRowIdManager { Location retval = alloc( length ); write( retval, data, start, length ); + return retval; } @@ -172,10 +173,13 @@ final class PhysicalRowIdManager throws IOException { Location retval = freeman.get( size ); - if ( retval == null ) { + + if ( retval == null ) + { // temporary work around for DIRSERVER-1459 retval = allocNew( size * 2, pageManager.getLast( Magic.USED_PAGE ) ); } + return retval; } Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Provider.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Provider.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Provider.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/Provider.java Thu Aug 25 18:09:19 2011 @@ -51,14 +51,13 @@ package jdbm.recman; import java.io.IOException; import java.util.Properties; -import org.apache.directory.server.i18n.I18n; - import jdbm.RecordManager; import jdbm.RecordManagerOptions; import jdbm.RecordManagerProvider; - import jdbm.helper.MRU; +import org.apache.directory.server.i18n.I18n; + /** * Provider of the default RecordManager implementation. * @@ -79,13 +78,9 @@ public final class Provider implements R */ public RecordManager createRecordManager( String name, Properties options ) throws IOException { - RecordManager recman; - String value; - int cacheSize; - - recman = new BaseRecordManager( name ); + RecordManager recman = new BaseRecordManager( name ); - value = options.getProperty( RecordManagerOptions.DISABLE_TRANSACTIONS, "false" ); + String value = options.getProperty( RecordManagerOptions.DISABLE_TRANSACTIONS, "false" ); if ( value.equalsIgnoreCase( "TRUE" ) ) { @@ -93,7 +88,7 @@ public final class Provider implements R } value = options.getProperty( RecordManagerOptions.CACHE_SIZE, "1000" ); - cacheSize = Integer.parseInt( value ); + int cacheSize = Integer.parseInt( value ); value = options.getProperty( RecordManagerOptions.CACHE_TYPE, RecordManagerOptions.NORMAL_CACHE ); Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/RecordFile.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/RecordFile.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/RecordFile.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/RecordFile.java Thu Aug 25 18:09:19 2011 @@ -47,8 +47,11 @@ package jdbm.recman; -import java.io.*; -import java.util.*; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; import org.apache.directory.server.i18n.I18n; @@ -67,24 +70,34 @@ public final class RecordFile // state transitions: free -> inUse -> dirty -> inTxn -> free // free is a cache, thus a FIFO. The rest are hashes. + /** The list of free pages */ private final LinkedList free = new LinkedList(); + + /** The map of pages being currently used */ private final HashMap inUse = new HashMap(); + + /** The map of dirty pages (page being modified) */ private final HashMap dirty = new HashMap(); + + /** The map of page in a transaction */ private final HashMap inTxn = new HashMap(); - // transactions disabled? + /** A flag set if transactions is disabled. Default to false */ private boolean transactionsDisabled = false; /** The length of a single block. */ - public final static int BLOCK_SIZE = 8192;//4096; + public final static int BLOCK_SIZE = 4096; /** The extension of a record file */ - final static String extension = ".db"; + final static String EXTENSION = ".db"; /** A block of clean data to wipe clean pages. */ final static byte[] cleanData = new byte[BLOCK_SIZE]; + /** The underlying file */ private RandomAccessFile file; + + /** The file name */ private final String fileName; @@ -97,29 +110,35 @@ public final class RecordFile * @throws IOException whenever the creation of the underlying * RandomAccessFile throws it. */ - RecordFile ( String fileName ) throws IOException + RecordFile( String fileName ) throws IOException { this.fileName = fileName; - file = new RandomAccessFile(fileName + extension, "rw"); + file = new RandomAccessFile( fileName + EXTENSION, "rw" ); } + /** + * @return The TransactionManager if the transaction system is enabled. + * @throws IOException If we can't create a TransactionManager + */ TransactionManager getTxnMgr() throws IOException { if ( transactionsDisabled ) { throw new IllegalStateException( "Transactions are disabled." ); } + if ( transactionManager == null ) { transactionManager = new TransactionManager( this ); } + return transactionManager; } /** - * Returns the file name. + * @return the file name. */ String getFileName() { @@ -142,85 +161,89 @@ public final class RecordFile * copy of the record, and thus can be written (and subsequently released * with a dirty flag in order to write the block back). * - * @param blockid The record number to retrieve. + * @param blockId The record number to retrieve. */ - BlockIo get( long blockid ) throws IOException + BlockIo get( long blockId ) throws IOException { // try in transaction list, dirty list, free list + BlockIo blockIo = inTxn.get( blockId ); - BlockIo node = inTxn.get( blockid ); - if ( node != null ) + if ( blockIo != null ) { - inTxn.remove( blockid ); - inUse.put( blockid, node ); - return node; + inTxn.remove( blockId ); + inUse.put( blockId, blockIo ); + + return blockIo; } - node = dirty.get( blockid ); - if ( node != null ) + blockIo = dirty.get( blockId ); + + if ( blockIo != null ) { - dirty.remove( blockid ); - inUse.put( blockid, node ); - return node; + dirty.remove( blockId ); + inUse.put( blockId, blockIo ); + + return blockIo; } - for ( Iterator i = free.iterator(); i.hasNext(); ) + for ( Iterator iterator = free.iterator(); iterator.hasNext(); ) { - BlockIo cur = i.next(); - if ( cur.getBlockId() == blockid ) + BlockIo cur = iterator.next(); + + if ( cur.getBlockId() == blockId ) { - node = cur; - i.remove(); - inUse.put( blockid, node ); - return node; + blockIo = cur; + iterator.remove(); + inUse.put( blockId, blockIo ); + + return blockIo; } } // sanity check: can't be on in use list - if ( inUse.get( blockid ) != null ) + if ( inUse.get( blockId ) != null ) { - throw new Error( I18n.err( I18n.ERR_554, blockid ) ); + throw new Error( I18n.err( I18n.ERR_554, blockId ) ); } // get a new node and read it from the file - node = getNewNode( blockid ); - long offset = blockid * BLOCK_SIZE; - if ( file.length() > 0 && offset <= file.length() ) + blockIo = getNewBlockIo( blockId ); + long offset = blockId * BLOCK_SIZE; + long fileLength = file.length(); + + if ( ( fileLength > 0 ) && ( offset <= fileLength ) ) { - read( file, offset, node.getData(), BLOCK_SIZE ); + read( file, offset, blockIo.getData(), BLOCK_SIZE ); } - else - { - System.arraycopy( cleanData, 0, node.getData(), 0, BLOCK_SIZE ); - } - inUse.put( blockid, node ); - node.setClean(); - return node; + inUse.put( blockId, blockIo ); + blockIo.setClean(); + + return blockIo; } /** * Releases a block. * - * @param blockid The record number to release. + * @param blockId The record number to release. * @param isDirty If true, the block was modified since the get(). */ - void release( long blockid, boolean isDirty ) throws IOException + void release( long blockId, boolean isDirty ) throws IOException { - BlockIo node = inUse.get( blockid ); + BlockIo blockIo = inUse.get( blockId ); - if ( node == null ) + if ( blockIo == null ) { - throw new IOException( I18n.err( I18n.ERR_555, blockid ) ); + throw new IOException( I18n.err( I18n.ERR_555, blockId ) ); } - if ( ! node.isDirty() && isDirty ) + if ( ! blockIo.isDirty() && isDirty ) { - node.setDirty(); + blockIo.setDirty(); } - release( node ); + release( blockIo ); } @@ -293,26 +316,25 @@ public final class RecordFile } - for ( Iterator i = dirty.values().iterator(); i.hasNext(); ) + for ( BlockIo blockIo : dirty.values() ) { - BlockIo node = ( BlockIo ) i.next(); - i.remove(); - // System.out.println("node " + node + " map size now " + dirty.size()); if ( transactionsDisabled ) { - long offset = node.getBlockId() * BLOCK_SIZE; + long offset = blockIo.getBlockId() * BLOCK_SIZE; file.seek( offset ); - file.write( node.getData() ); - node.setClean(); - free.add( node ); + file.write( blockIo.getData() ); + blockIo.setClean(); + free.add( blockIo ); } else { - getTxnMgr().add( node ); - inTxn.put( node.getBlockId(), node ); + getTxnMgr().add( blockIo ); + inTxn.put( blockIo.getBlockId(), blockIo ); } } + + dirty.clear(); if ( ! transactionsDisabled ) { @@ -421,39 +443,45 @@ public final class RecordFile /** - * Returns a new node. The node is retrieved (and removed) from the + * Returns a new BlockIo. The BlockIo is retrieved (and removed) from the * released list or created new. */ - private BlockIo getNewNode( long blockid ) throws IOException + private BlockIo getNewBlockIo( long blockId ) throws IOException { - BlockIo retval = null; + BlockIo blockIo = null; if ( ! free.isEmpty() ) { - retval = ( BlockIo ) free.removeFirst(); + blockIo = ( BlockIo ) free.removeFirst(); + blockIo.setBlockId( blockId ); } - if ( retval == null ) + if ( blockIo == null ) { - retval = new BlockIo( 0, new byte[BLOCK_SIZE] ); + blockIo = new BlockIo( blockId, new byte[BLOCK_SIZE] ); } - retval.setBlockId(blockid); - retval.setView( null ); - return retval; + blockIo.setView( null ); + + return blockIo; } /** - * Synchronizes a node to disk. This is called by the transaction manager's + * Synchronizes a BlockIo to disk. This is called by the transaction manager's * synchronization code. + * + * @param blockIo The blocIo to write on disk + * @exception IOException If we have a problem while trying to write the blockIo to disk */ - void synch( BlockIo node ) throws IOException + void sync( BlockIo blockIo ) throws IOException { - byte[] data = node.getData(); + byte[] data = blockIo.getData(); + if ( data != null ) { - long offset = node.getBlockId() * BLOCK_SIZE; + // Write the data to disk now. + long offset = blockIo.getBlockId() * BLOCK_SIZE; file.seek( offset ); file.write( data ); } Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TransactionManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TransactionManager.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TransactionManager.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TransactionManager.java Thu Aug 25 18:09:19 2011 @@ -250,7 +250,7 @@ public final class TransactionManager { // write block vector elements to the data file. while ( blockIterator.hasNext() ) { BlockIo cur = (BlockIo)blockIterator.next(); - owner.synch(cur); + owner.sync(cur); if (fromCore) { cur.decrementTransactionCount(); if (!cur.isInTransaction()) { Modified: directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TranslationPage.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TranslationPage.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TranslationPage.java (original) +++ directory/apacheds/trunk/jdbm/src/main/java/jdbm/recman/TranslationPage.java Thu Aug 25 18:09:19 2011 @@ -47,6 +47,7 @@ package jdbm.recman; + /** * Class describing a page that holds translations from physical rowids * to logical rowids. In fact, the page just holds physical rowids - the @@ -78,6 +79,7 @@ final class TranslationPage extends Page static TranslationPage getTranslationPageView( BlockIo block ) { BlockView view = block.getView(); + if ( view != null && view instanceof TranslationPage ) { return ( TranslationPage ) view; @@ -93,10 +95,12 @@ final class TranslationPage extends Page PhysicalRowId get( short offset ) { int slot = ( offset - O_TRANS ) / PhysicalRowId.SIZE; + if ( slots[slot] == null ) { slots[slot] = new PhysicalRowId( block, offset ); } + return slots[slot]; } } Modified: directory/apacheds/trunk/jdbm/src/test/java/jdbm/btree/StreamCorrupted.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/test/java/jdbm/btree/StreamCorrupted.java?rev=1161673&r1=1161672&r2=1161673&view=diff ============================================================================== --- directory/apacheds/trunk/jdbm/src/test/java/jdbm/btree/StreamCorrupted.java (original) +++ directory/apacheds/trunk/jdbm/src/test/java/jdbm/btree/StreamCorrupted.java Thu Aug 25 18:09:19 2011 @@ -46,13 +46,12 @@ package jdbm.btree; +import java.io.File; +import java.io.IOException; + import jdbm.RecordManager; import jdbm.RecordManagerFactory; import jdbm.helper.StringComparator; -import jdbm.btree.BTree; - -import java.io.File; -import java.io.IOException; import org.junit.Test; @@ -130,9 +129,9 @@ public class StreamCorrupted @Test public void testStreamCorrupted() throws IOException { - RecordManager recman; - BTree btree; - int iterations; + RecordManager recman; + BTree btree; + int iterations; iterations = 100; // 23 works :-((((( Added: directory/apacheds/trunk/jdbm/src/test/java/jdbm/recman/BlockIoTest.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm/src/test/java/jdbm/recman/BlockIoTest.java?rev=1161673&view=auto ============================================================================== --- directory/apacheds/trunk/jdbm/src/test/java/jdbm/recman/BlockIoTest.java (added) +++ directory/apacheds/trunk/jdbm/src/test/java/jdbm/recman/BlockIoTest.java Thu Aug 25 18:09:19 2011 @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package jdbm.recman; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.Before; +import org.junit.Test; + +public class BlockIoTest +{ + BlockIo blockIo; + BlockIo blockIoData; + + @Before + public void init() + { + blockIo = new BlockIo( 0L, new byte[1024] ); + + // Init the blockIo with 1024 bytes from 0x00 to 0xFF, 4 times + for ( int i = 0; i < 1024; i++ ) + { + blockIo.writeByte( i, (byte)( i & 0x00fff ) ); + } + + blockIoData = new BlockIo( 0L, new byte[1024] ); + blockIoData.writeLong( 0, 0x8081828384858687L ); + blockIoData.writeInt( 8, 0x000000ff ); + + for ( int i = 0; i < 256; i++ ) + { + blockIoData.writeByte( 12+i, (byte)0x80 ); + } + } + + + @Test + public void testReadByte() + { + assertEquals( (byte)0x00, blockIo.readByte( 0 ) ); + assertEquals( (byte)0xff, blockIo.readByte( 1023 ) ); + + try + { + blockIo.readByte( -1 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + + try + { + blockIo.readByte( 1024 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + } + + + @Test + public void testReadInt() + { + assertEquals( 0x00010203, blockIo.readInt( 0 ) ); + assertEquals( 0x7c7d7e7f, blockIo.readInt( 124 ) ); + assertEquals( 0x7d7e7f80, blockIo.readInt( 125 ) ); + assertEquals( 0x7e7f8081, blockIo.readInt( 126 ) ); + assertEquals( 0x7f808182, blockIo.readInt( 127 ) ); + assertEquals( 0x80818283, blockIo.readInt( 128 ) ); + assertEquals( 0xfbfcfdfe, blockIo.readInt( 1019 ) ); + assertEquals( 0xfcfdfeff, blockIo.readInt( 1020 ) ); + + try + { + blockIo.readInt( -1 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + + try + { + blockIo.readInt( 1021 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + + try + { + blockIo.readInt( 1024 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + } + + + @Test + public void testReadShort() + { + assertEquals( 0x0001, blockIo.readShort( 0 ) ); + assertEquals( 0x7c7d, blockIo.readShort( 124 ) ); + assertEquals( 0x7d7e, blockIo.readShort( 125 ) ); + assertEquals( 0x7e7f, blockIo.readShort( 126 ) ); + assertEquals( 0x7f80, blockIo.readShort( 127 ) ); + assertEquals( (short)0x8081, blockIo.readShort( 128 ) ); + assertEquals( (short)0xfdfe, blockIo.readShort( 1021 ) ); + assertEquals( (short)0xfeff, blockIo.readShort( 1022 ) ); + + try + { + blockIo.readShort( -1 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + + try + { + blockIo.readShort( 1023 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + + try + { + blockIo.readShort( 1024 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + } + + + @Test + public void testReadLong() + { + assertEquals( 0x0001020304050607L, blockIo.readLong( 0 ) ); + assertEquals( 0x78797a7b7c7d7e7fL, blockIo.readLong( 120 ) ); + assertEquals( 0x797a7b7c7d7e7f80L, blockIo.readLong( 121 ) ); + assertEquals( 0x7a7b7c7d7e7f8081L, blockIo.readLong( 122 ) ); + assertEquals( 0x7b7c7d7e7f808182L, blockIo.readLong( 123 ) ); + assertEquals( 0x7c7d7e7f80818283L, blockIo.readLong( 124 ) ); + assertEquals( 0x7d7e7F8081828384L, blockIo.readLong( 125 ) ); + assertEquals( 0x7e7f808182838485L, blockIo.readLong( 126 ) ); + assertEquals( 0x7f80818283848586L, blockIo.readLong( 127 ) ); + assertEquals( 0x8081828384858687L, blockIo.readLong( 128 ) ); + assertEquals( 0xf7f8f9fafbfcfdfeL, blockIo.readLong( 1015 ) ); + assertEquals( 0xf8f9fafbfcfdfeffL, blockIo.readLong( 1016 ) ); + + try + { + blockIo.readLong( -1 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + + try + { + blockIo.readLong( 1017 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + + try + { + blockIo.readLong( 1024 ); + fail(); + } + catch ( ArrayIndexOutOfBoundsException aioobe ) + { + // Expected + } + } +}