You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2012/02/02 13:38:42 UTC

svn commit: r1239581 [7/9] - in /directory/apacheds/trunk/jdbm2: ./ src/ src/etc/ src/examples/ src/main/ src/main/java/ src/main/java/jdbm/ src/main/java/jdbm/btree/ src/main/java/jdbm/helper/ src/main/java/jdbm/htree/ src/main/java/jdbm/recman/ src/s...

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,237 @@
+/**
+ * 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: FreePhysicalRowIdPage.java,v 1.1 2000/05/06 00:00:31 boisvert Exp $
+ */
+package jdbm.recman;
+
+
+
+/**
+ * Class describing a page that holds physical rowids that were freed.
+ */
+final class FreePhysicalRowIdPage extends PageHeader 
+{
+    // offsets
+    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 ) / FreePhysicalRowId.SIZE;
+    
+    // slots we returned.
+    FreePhysicalRowId[] slots = new FreePhysicalRowId[ELEMS_PER_PAGE];
+
+    
+    /**
+     * Constructs a data page view from the indicated block.
+     */
+    FreePhysicalRowIdPage( BlockIo block ) 
+    {
+        super( block );
+    }
+    
+
+    /**
+     * Factory method to create or return a data page for the indicated block.
+     */
+    static FreePhysicalRowIdPage getFreePhysicalRowIdPageView( BlockIo block ) 
+    {
+        BlockView view = block.getView();
+        
+        if ( view != null && view instanceof FreePhysicalRowIdPage )
+        {
+            return ( FreePhysicalRowIdPage ) view;
+        }
+        else
+        {
+            return new FreePhysicalRowIdPage( block );
+        }
+    }
+    
+
+    /** 
+     * Returns the number of free rowids 
+     */
+    short getCount() 
+    {
+        return blockIo.readShort( O_COUNT );
+    }
+
+    
+    /** 
+     * Sets the number of free rowids 
+     */
+    private void setCount( short i ) 
+    {
+        blockIo.writeShort( O_COUNT, i );
+    }
+
+    
+    /** 
+     * Frees a slot 
+     */
+    void free( int slot ) 
+    {
+        get( slot ).setSize( 0 );
+        setCount( ( short ) ( getCount() - 1 ) );
+    }
+
+    
+    /** 
+     * Allocates a slot 
+     */
+    FreePhysicalRowId alloc( int slot ) 
+    {
+        setCount( ( short ) ( getCount() + 1 ) );
+        return get( slot );
+    }
+
+    
+    /** 
+     * Returns true if a slot is allocated 
+     */
+    boolean isAllocated( int slot ) 
+    {
+        return get( slot ).getSize() != 0;
+    }
+    
+
+    /** 
+     * Returns true if a slot is free 
+     */
+    boolean isFree( int slot ) 
+    {
+        return ! isAllocated( slot );
+    }
+    
+    
+    /** 
+     * Returns the value of the indicated slot 
+     */
+    FreePhysicalRowId get( int slot ) 
+    {
+        if ( slots[slot] == null )
+        {
+            slots[slot] = new FreePhysicalRowId( blockIo, slotToOffset( slot ) ) ;
+        }
+  
+        return slots[slot];
+    }
+    
+
+    /** 
+     * Converts slot to offset 
+     */
+    short slotToOffset( int slot ) 
+    {
+        return ( short ) ( O_FREE + ( slot * FreePhysicalRowId.SIZE ) );
+    }
+    
+    
+    /** 
+     * @return first free slot, -1 if no slots are available
+     */
+    int getFirstFree() 
+    {
+        for ( int i = 0; i < ELEMS_PER_PAGE; i++ ) 
+        {
+            if ( isFree( i ) )
+            {
+                return i;
+            }
+        }
+  
+        return -1;
+    }
+    
+
+    /** 
+     * @return first slot with available size >= indicated size, or -1 if no 
+     * slots are available.
+     */
+    int getFirstLargerThan( int size ) 
+    {
+        for ( int i = 0; i < ELEMS_PER_PAGE; i++ ) 
+        {
+            if ( isAllocated( i ) && get( i ).getSize() >= size )
+            {
+                return i;
+            }
+        }
+  
+        return -1;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() 
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        sb.append( "FreePhysRowIdPage ( " );
+        
+        // The blockIO
+        sb.append( super.toString() ).append( ", " );
+        
+        // The first rowId
+        sb.append( "count: " ).append( getCount() );
+        
+        // Dump the Physical row id
+        for ( int i = 0; i < ELEMS_PER_PAGE; i++ )
+        {
+            if ( slots[i] != null )
+            {
+                sb.append( ", [" ).append( i ).append( "]=<" ).
+                append( slots[i].getBlock() ).append( ", " ).
+                append( slots[i].getOffset() ).append( ", " ).
+                append( slots[i].getSize() ).append( ">" );
+            }
+        }
+        
+        sb.append( ")" );
+        
+        return sb.toString();
+    }
+}
\ No newline at end of file

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/FreePhysicalRowIdPageManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/FreePhysicalRowIdPageManager.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/FreePhysicalRowIdPageManager.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/FreePhysicalRowIdPageManager.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,161 @@
+/**
+ * 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: FreePhysicalRowIdPageManager.java,v 1.2 2001/11/17 16:14:25 boisvert Exp $
+ */
+package jdbm.recman;
+
+
+import java.io.IOException;
+
+
+/**
+ * This class manages free physical rowid pages and provides methods to free 
+ * and allocate physical rowids at a high level.
+ */
+final class FreePhysicalRowIdPageManager
+{
+    // our record recordFile
+    protected RecordFile recordFile;
+
+    // our page manager
+    protected PageManager pageManager;
+
+    
+    /**
+     * Creates a new instance using the indicated record recordFile and page manager.
+     */
+    FreePhysicalRowIdPageManager( PageManager pageManager ) throws IOException
+    {
+        this.recordFile = pageManager.getRecordFile();
+        this.pageManager = pageManager;
+    }
+
+
+    /**
+     * Returns a free physical rowid of the indicated size, or null if nothing 
+     * was found.
+     */
+    Location get( int size ) throws IOException
+    {
+        // Loop through the free physical rowid list until we find a rowid 
+        // that's large enough.
+        Location retval = null;
+        PageCursor curs = new PageCursor( pageManager, Magic.FREEPHYSIDS_PAGE );
+
+        while ( curs.next() != 0 ) 
+        {
+            FreePhysicalRowIdPage fp = FreePhysicalRowIdPage
+                .getFreePhysicalRowIdPageView( recordFile.get( curs.getBlockId() ) );
+            int slot = fp.getFirstLargerThan( size );
+            
+            if ( slot != -1 ) 
+            {
+                // got one!
+                retval = new Location( fp.get( slot ) );
+
+                fp.free( slot );
+                if ( fp.getCount() == 0 ) 
+                {
+                    // page became empty - free it
+                    recordFile.release( curs.getBlockId(), false );
+                    pageManager.free( Magic.FREEPHYSIDS_PAGE, curs.getBlockId() );
+                } 
+                else 
+                {
+                    recordFile.release( curs.getBlockId(), true );
+                }
+
+                return retval;
+            } 
+            else 
+            {
+                // no luck, go to next page
+                recordFile.release( curs.getBlockId(), false );
+            }
+        }
+        return null;
+    }
+    
+
+    /**
+     * Puts the indicated rowid on the free list.
+     */
+    void put( Location rowid, int size ) throws IOException 
+    {
+        FreePhysicalRowId free = null;
+        PageCursor curs = new PageCursor( pageManager, Magic.FREEPHYSIDS_PAGE );
+        long freePage = 0;
+        
+        while ( curs.next() != 0 ) 
+        {
+            freePage = curs.getBlockId();
+            BlockIo curBlock = recordFile.get( freePage );
+            FreePhysicalRowIdPage fp = FreePhysicalRowIdPage.getFreePhysicalRowIdPageView( curBlock );
+            int slot = fp.getFirstFree();
+      
+            if ( slot != -1 ) 
+            {
+                free = fp.alloc( slot );
+                break;
+            }
+
+            recordFile.release( curBlock );
+        }
+  
+        if ( free == null ) 
+        {
+            // No more space on the free list, add a page.
+            freePage = pageManager.allocate( Magic.FREEPHYSIDS_PAGE );
+            BlockIo curBlock = recordFile.get( freePage );
+            FreePhysicalRowIdPage fp = FreePhysicalRowIdPage.getFreePhysicalRowIdPageView( curBlock );
+            free = fp.alloc( 0 );
+        }
+
+        free.setBlock( rowid.getBlock() );
+        free.setOffset( rowid.getOffset() );
+        free.setSize( size );
+        recordFile.release( freePage, true );
+    }
+}

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Location.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Location.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Location.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Location.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,168 @@
+/**
+ * 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: Location.java,v 1.2 2003/11/01 14:17:21 dranatunga Exp $
+ */
+package jdbm.recman;
+
+
+/**
+ * This class represents a location within a file. Both physical and
+ * logical rowids are based on locations internally - this version is
+ * used when there is no file block to back the location's data.
+ */
+final class Location 
+{
+    /** The block in which the data is stored */
+    private long blockId;
+    
+    /** The offset within this block */
+    private short offset;
+
+    
+    /**
+     * Creates a location from a (block, offset) tuple.
+     * 
+     * @param blockId The block identifier
+     * @param offset the offset in the block
+     */
+    Location( long blockId, short offset ) 
+    {
+        this.blockId = blockId;
+        this.offset = offset;
+    }
+
+    
+    /**
+     * Creates a location from a combined block/offset long, as used in the 
+     * external representation of logical rowids. A recid is a logical rowid.
+     * 
+     * @param blockOffset The block + offset combinaison
+     */
+    Location( long blockOffset ) 
+    {
+        this.offset = ( short ) ( blockOffset & 0xffff );
+        this.blockId = blockOffset >> 16;
+    }
+
+    
+    /**
+     * Creates a location based on the data of the physical rowid.
+     * 
+     * @param physicalRowId The physical row id used as a base for the Location creation
+     */
+    Location( PhysicalRowId physicalRowId ) 
+    {
+        blockId = physicalRowId.getBlock();
+        offset = physicalRowId.getOffset();
+    }
+
+    
+    /**
+     * @eturn the blockId of the location
+     */
+    long getBlock() 
+    {
+        return blockId;
+    }
+
+    
+    /**
+     * Returns the offset within the block of the location
+     */
+    short getOffset() 
+    {
+        return offset;
+    }
+
+    
+    /**
+     * Returns the external representation of a location when used
+     * as a logical rowid, which combines the block and the offset
+     * in a single long.
+     */
+    long toLong() 
+    {
+        return ( blockId << 16 ) + ( long ) offset;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        return 663;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+   public boolean equals( Object o ) 
+    {
+        if ( ( o == null ) || ! ( o instanceof Location ) )
+        {
+            return false;
+        }
+        
+        Location ol = ( Location ) o;
+        
+        return ( ol.blockId == blockId ) && ( ol.offset == offset );
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() 
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append( "Location ( " ).append( blockId ).append( " : " );
+        sb.append( offset ).append( " ) " );
+        
+        return sb.toString();
+    }
+}

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/LogicalRowIdManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/LogicalRowIdManager.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/LogicalRowIdManager.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/LogicalRowIdManager.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,158 @@
+/**
+ * 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: LogicalRowIdManager.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 manages the linked lists of logical rowid pages.
+ */
+final class LogicalRowIdManager
+{
+    // our record recordFile and associated page manager
+    private RecordFile recordFile;
+    private PageManager pageManager;
+    private FreeLogicalRowIdPageManager freeman;
+
+
+    /**
+     *  Creates a log rowid manager using the indicated record recordFile and
+     *  page manager
+     */
+    LogicalRowIdManager( PageManager pageManager ) throws IOException
+    {
+        this.recordFile = pageManager.getRecordFile();
+        this.pageManager = pageManager;
+        this.freeman = new FreeLogicalRowIdPageManager( pageManager );
+    }
+
+
+    /**
+     *  Creates a new logical rowid pointing to the indicated physical
+     *  id
+     */
+    Location insert( Location loc ) throws IOException
+    {
+        // check whether there's a free rowid to reuse
+        Location retval = freeman.get();
+        if ( retval == null )
+        {
+            // no. This means that we bootstrap things by allocating
+            // a new translation page and freeing all the rowids on it.
+            long firstPage = pageManager.allocate( Magic.TRANSLATION_PAGE );
+            short curOffset = TranslationPage.O_TRANS;
+            for ( int i = 0; i < TranslationPage.ELEMS_PER_PAGE; i++ )
+            {
+                freeman.put( new Location( firstPage, curOffset ) );
+                curOffset += PhysicalRowId.SIZE;
+            }
+            retval = freeman.get();
+            if ( retval == null )
+            {
+                throw new Error( I18n.err( I18n.ERR_545 ) );
+            }
+        }
+        // write the translation.
+        update( retval, loc );
+        return retval;
+    }
+
+
+    /**
+     *  Releases the indicated logical rowid.
+     */
+    void delete( Location rowid ) throws IOException
+    {
+
+        freeman.put( rowid );
+    }
+
+
+    /**
+     *  Updates the mapping
+     *
+     *  @param rowid The logical rowid
+     *  @param loc The physical rowid
+     */
+    void update( Location rowid, Location loc ) throws IOException
+    {
+
+        TranslationPage xlatPage = TranslationPage.getTranslationPageView( recordFile.get( rowid.getBlock() ) );
+        PhysicalRowId physid = xlatPage.get( rowid.getOffset() );
+        physid.setBlock( loc.getBlock() );
+        physid.setOffset( loc.getOffset() );
+        recordFile.release( rowid.getBlock(), true );
+    }
+
+
+    /**
+     *  Returns a mapping
+     *
+     *  @param rowid The logical rowid
+     *  @return The physical rowid
+     */
+    Location fetch( Location rowid ) throws IOException
+    {
+        TranslationPage xlatPage = TranslationPage.getTranslationPageView( recordFile.get( rowid.getBlock() ) );
+        
+        try
+        {
+            Location retval = new Location( xlatPage.get( rowid.getOffset() ) );
+            return retval;
+        }
+        finally
+        {
+            recordFile.release( rowid.getBlock(), false );
+        }
+    }
+
+}

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Magic.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Magic.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Magic.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Magic.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,99 @@
+/**
+ * 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: Magic.java,v 1.1 2000/05/06 00:00:31 boisvert Exp $
+ */
+package jdbm.recman;
+
+
+/**
+ * This interface contains magic cookies.
+ * Final reference -> class shouldn't be extended
+ */
+public final class Magic 
+{
+    /**
+     *  Ensures no construction of this class, also ensures there is no need for final keyword above
+     *  (Implicit super constructor is not visible for default constructor),
+     *  but is still self documenting.
+     */
+    private Magic()
+    {
+    }
+
+    
+    /** Magic cookie at start of file */
+    public final static short FILE_HEADER = 0x1350;
+
+    /** Magic for blocks. They're offset by the block type magic codes. */
+    public final static short BLOCK = 0x1351;
+
+    /** Magics for block types in certain lists. Offset by baseBlockMagic */
+    public final static short FREE_PAGE = 0;
+    public final static short USED_PAGE = 1;
+    public final static short TRANSLATION_PAGE = 2;
+    public final static short FREELOGIDS_PAGE = 3;
+    public final static short FREEPHYSIDS_PAGE = 4;
+
+    /** Number of lists in a file */
+    public final static short NLISTS = 5;
+
+    /**
+     *  Maximum number of blocks in a file, leaving room for a 16 bit
+     *  offset encoded within a long.
+     */
+    public final static long MAX_BLOCKS = 0x7FFFFFFFFFFFL;
+
+    /** Magic for transaction file */
+    public final static short LOGFILE_HEADER = 0x1360;
+
+    /** Size of an externalized byte */
+    public final static short SZ_BYTE = 1;
+    /** Size of an externalized short */
+    public final static short SZ_SHORT = 2;
+    /** Size of an externalized int */
+    public final static short SZ_INT = 4;
+    /** Size of an externalized long */
+    public final static short SZ_LONG = 8;
+}

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageCursor.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageCursor.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageCursor.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,139 @@
+/**
+ * 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: PageCursor.java,v 1.1 2000/05/06 00:00:31 boisvert Exp $
+ */
+package jdbm.recman;
+
+
+import java.io.IOException;
+
+
+/**
+ * This class provides a cursor that can follow lists of pages bi-directionally.
+ */
+final class PageCursor 
+{
+    /** The PageManager */
+    PageManager pageManager;
+    
+    /** The current block ID */
+    long blockId;
+    
+    /** The page type */
+    short type;
+    
+
+    /**
+     * Constructs a page cursor that starts at the indicated block.
+     * 
+     * @param pageManager The PageManager
+     */
+    PageCursor( PageManager pageManager, long blockId ) 
+    {
+        this.pageManager = pageManager;
+        this.blockId = blockId;
+    }
+    
+    
+    /**
+     * Constructs a page cursor that starts at the first block of the 
+     * indicated list.
+     * 
+     * @param pageManager The PageManager
+     * @param type The page type
+     */
+    PageCursor( PageManager pageManager, short type ) throws IOException 
+    {
+        this.pageManager = pageManager;
+        this.type = type;
+    }
+    
+    
+    /**
+     * @return the BlockId
+     */
+    long getBlockId() throws IOException 
+    {
+        return blockId;
+    }
+    
+    
+    /**
+     * @return the next blockId 
+     */
+    long next() throws IOException 
+    {
+        if ( blockId == 0 )
+        {
+            blockId = pageManager.getFirst( type );
+        }
+        else
+        {
+            blockId = pageManager.getNext( blockId );
+        }
+        
+        return blockId;
+    } 
+    
+    
+    /**
+     * @return the previous blockId
+     */
+    long prev() throws IOException 
+    {
+        blockId = pageManager.getPrev( blockId );
+        
+        return blockId;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return "Location( " + blockId + ", " + type + ")";
+    }
+}

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageHeader.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageHeader.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageHeader.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageHeader.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,295 @@
+/**
+ * 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: PageHeader.java,v 1.2 2003/09/21 15:47:01 boisvert Exp $
+ */
+package jdbm.recman;
+
+
+import java.io.IOException;
+
+import org.apache.directory.server.i18n.I18n;
+
+
+/**
+ * This class represents a page header. It is the common superclass for
+ * all different page views. It contains the following information:
+ * 
+ * <ol>
+ *   <li>2 bytes: the short block type code</li>
+ *   <li>8 bytes: the long block id of the next block in the block list</li>
+ *   <li>8 bytes: the long block id of the previous block in the block list</li>
+ *   <li>4 bytes: the size of this page
+ * </ol>
+ * 
+ * The page header block view hence sees 18 bytes of page header data.
+ */
+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 */
+    protected static final short SIZE = O_PREV + Magic.SZ_LONG;
+
+    /** the page header block this view is associated with */
+    protected BlockIo blockIo;
+
+    
+    /**
+     * Constructs a PageHeader object from a block
+     *
+     * @param blockIo The block that contains the page header
+     * @throws IOException if the block is too short to keep the page header.
+     */
+    protected PageHeader( BlockIo blockIo ) 
+    {
+        this.blockIo = blockIo;
+        blockIo.setView( this );
+        
+        if ( ! magicOk() )
+        {
+            throw new Error( I18n.err( I18n.ERR_546, blockIo.getBlockId(), getMagic() ) );
+        }
+    }
+    
+    
+    /**
+     * Constructs a new PageHeader of the indicated type. Used for newly
+     * created pages.
+     */
+    PageHeader( BlockIo blockIo, short type ) 
+    {
+        this.blockIo = blockIo;
+        blockIo.setView( this );
+        setType( type );
+    }
+    
+    
+    /**
+     * Factory method to create or return a page header for the indicated block.
+     */
+    static PageHeader getView ( BlockIo blockIo ) 
+    {
+        BlockView view = blockIo.getView();
+        
+        if ( view != null && view instanceof PageHeader )
+        {
+            return ( PageHeader ) view;
+        }
+        else
+        {
+            return new PageHeader( blockIo );
+        }
+    }
+    
+    
+    /**
+     * Returns true if the magic corresponds with the fileHeader magic.
+     */
+    private boolean magicOk() 
+    {
+        int magic = getMagic();
+        
+        return magic >= Magic.BLOCK
+            && magic <= ( Magic.BLOCK + Magic.FREEPHYSIDS_PAGE );
+    }
+    
+    
+    /**
+     * For paranoia mode
+     */
+    protected void paranoiaMagicOk() 
+    {
+        if ( ! magicOk() )
+        {
+            throw new Error( I18n.err( I18n.ERR_547, getMagic() ) );
+        }
+    }
+    
+    
+    /** 
+     * @return The magic code (ie, the 2 first bytes of the inner BlockIo) 
+     */
+    short getMagic() 
+    {
+        return blockIo.readShort( O_MAGIC );
+    }
+
+    
+    /**
+     * @return the next block (ie the long at position 2 in the BlockIo)
+     */
+    long getNext() 
+    {
+        paranoiaMagicOk();
+        
+        return blockIo.readLong( O_NEXT );
+    }
+    
+    
+    /** 
+     * Sets the next blockIo.
+     * 
+     * @param The next Block ID
+     */
+    void setNext( long next ) 
+    {
+        paranoiaMagicOk();
+        blockIo.writeLong( O_NEXT, next );
+    }
+    
+    
+    /** 
+     * @return the previous block (ie the long at position 10 in the BlockIo)
+     */
+    long getPrev() 
+    {
+        paranoiaMagicOk();
+        
+        return blockIo.readLong( O_PREV );
+    }
+    
+    
+    /** 
+     * Sets the previous block. 
+     */
+    void setPrev( long prev ) 
+    {
+        paranoiaMagicOk();
+        blockIo.writeLong( O_PREV, prev );
+    }
+    
+    
+    /** 
+     * Sets the type of the page header
+     * 
+     *  @param type The PageHeader type to store at position 0
+     */
+    void setType( short type ) 
+    {
+        blockIo.writeShort( O_MAGIC, ( short ) ( Magic.BLOCK + type ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() 
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        sb.append( "PageHeader ( " );
+        
+        // The blockIO
+        sb.append( "BlockIO ( " );
+        
+        // The blockID
+        sb.append( blockIo.getBlockId() ).append( ", " );
+        
+        // Is it dirty ?
+        if ( blockIo.isDirty() )
+        {
+            sb.append( "dirty, " );
+        }
+        else
+        {
+            sb.append( "clean, " );
+        }
+        
+        // The transaction count
+        if ( blockIo.isInTransaction() )
+        {
+            sb.append( "in tx" );
+        }
+        else
+        {
+            sb.append( "no tx" );
+        }
+
+        sb.append( " ), " );
+        
+        // The Type
+        int magic = getMagic();
+        
+        switch ( magic - Magic.BLOCK )
+        {
+            case Magic.FREE_PAGE :
+                sb.append( "FREE_PAGE" ).append( ", " );
+                break;
+                
+            case Magic.USED_PAGE :
+                sb.append( "USED_PAGE" ).append( ", " );
+                break;
+                
+            case Magic.TRANSLATION_PAGE :
+                sb.append( "TRANSLATION_PAGE" ).append( ", " );
+                break;
+                
+            case Magic.FREELOGIDS_PAGE :
+                sb.append( "FREELOGIDS_PAGE" ).append( ", " );
+                break;
+                
+            case Magic.FREEPHYSIDS_PAGE :
+                sb.append( "FREEPHYSIDS_PAGE" ).append( ", " );
+                break;
+                
+        }
+        
+        // The previous page
+        sb.append( "[p:" ).append( getPrev() ).append( ", " );
+        
+        // The next page
+        sb.append( "n:" ).append( getNext() ).append( "] )" );
+        
+        return sb.toString();
+    }
+}

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageManager.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageManager.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PageManager.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,353 @@
+/**
+ * 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: PageManager.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 manages the linked lists of pages that make up a recordFile. It contains
+ * a FileHeadrer and a reference to the recordFile it manages.<br/>
+ */
+final class PageManager 
+{
+    /** our record recordFile */
+    private RecordFile recordFile;
+    
+    /** header data */
+    private FileHeader header;
+    
+    /** 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 
+    {
+        this.recordFile = recordFile;
+        
+        // Note that we hold on to the recordFile header node.
+        headerBuf = recordFile.get( 0 );
+        
+        // Assume recordFile is new if the recordFile header's magic number is 0. 
+        boolean isNew = headerBuf.readShort( 0 ) == 0;
+
+        header = new FileHeader( headerBuf, isNew );
+    }
+    
+    
+    /**
+     * 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 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( freeBlock ) );
+        }
+        else 
+        {
+            // nope. make a new record
+            freeBlock = header.getLastOf( Magic.FREE_PAGE );
+
+            if ( freeBlock == 0 )
+            {
+                // very new recordFile - allocate record #1
+                freeBlock = 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( freeBlock );
+        PageHeader pageHdr = null;
+        
+        if ( isNew )
+        {
+            pageHdr = new PageHeader( buf, type );
+        }
+        else
+        {
+            pageHdr = PageHeader.getView( buf );
+        }
+        
+        long oldLast = header.getLastOf( type );
+        
+        // Clean data.
+        System.arraycopy( RecordFile.cleanData, 0, buf.getData(), 0, RecordFile.BLOCK_SIZE );
+        pageHdr.setType( type );
+        pageHdr.setPrev( oldLast );
+        pageHdr.setNext( 0 );
+        
+        if ( oldLast == 0 )
+        {
+            // This was the first one of this type
+            header.setFirstOf( type, freeBlock );
+        }
+        
+        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( freeBlock );
+            recordFile.release( oldLast, true );
+        }
+        
+        // remove the view, we have modified the type.
+        buf.setView( null );
+        
+        return freeBlock;
+    }
+    
+    
+    /**
+     * Frees a page of the indicated type.
+     */
+    void free( short type, long recid ) throws IOException 
+    {
+        if ( type == Magic.FREE_PAGE )
+        {
+            throw new Error( I18n.err( I18n.ERR_549 ) );
+        }
+        
+        if ( recid == 0 )
+        {
+            throw new Error( I18n.err( I18n.ERR_550 ) );
+        }
+        
+        // get the page and read next and previous pointers
+        BlockIo buf = recordFile.get( recid );
+        PageHeader pageHdr = PageHeader.getView( buf );
+        long prev = pageHdr.getPrev();
+        long next = pageHdr.getNext();
+        
+        // put the page at the front of the free list.
+        pageHdr.setType( Magic.FREE_PAGE );
+        pageHdr.setNext( header.getFirstOf( Magic.FREE_PAGE ) );
+        pageHdr.setPrev( 0 );
+        
+        header.setFirstOf( Magic.FREE_PAGE, recid );
+        recordFile.release( recid, true );
+        
+        // remove the page from its old list
+        if ( prev != 0 ) 
+        {
+            buf = recordFile.get( prev );
+            pageHdr = PageHeader.getView( buf );
+            pageHdr.setNext( next );
+            recordFile.release( prev, true );
+        }
+        else 
+        {
+            header.setFirstOf( type, next );
+        }
+        
+        if ( next != 0 ) 
+        {
+            buf = recordFile.get( next );
+            pageHdr = PageHeader.getView( buf );
+            pageHdr.setPrev( prev );
+            recordFile.release( next, true );
+        }
+        else 
+        {
+            header.setLastOf( type, prev );
+        }
+    }
+    
+    
+    /**
+     * Returns the page following the indicated block
+     */
+    long getNext( long block ) throws IOException 
+    {
+        try 
+        {
+            return PageHeader.getView( recordFile.get( block ) ).getNext();
+        } 
+        finally 
+        {
+            recordFile.release( block, false );
+        }
+    }
+    
+    
+    /**
+     * Returns the page before the indicated block
+     */
+    long getPrev( long block ) throws IOException 
+    {
+        try 
+        {
+            return PageHeader.getView( recordFile.get( block ) ).getPrev();
+        } 
+        finally 
+        {
+            recordFile.release( block, false );
+        }
+    }
+    
+    
+    /**
+     * Returns the first page on the indicated list.
+     */
+    long getFirst( short type ) throws IOException 
+    {
+        return header.getFirstOf( type );
+    }
+
+    
+    /**
+     * Returns the last page on the indicated list.
+     */
+    long getLast( short type ) throws IOException 
+    {
+        return header.getLastOf( type );
+    }
+    
+    
+    /**
+     * Commit all pending (in-memory) data by flushing the page manager.
+     * This forces a flush of all outstanding blocks (this is an implicit
+     * {@link RecordFile#commit} as well).
+     */
+    void commit() throws IOException 
+    {
+        // write the header out
+        recordFile.release( headerBuf );
+        recordFile.commit();
+
+        // and obtain it again
+        headerBuf = recordFile.get( 0 );
+        header = new FileHeader( headerBuf, false );
+    }
+
+    
+    /**
+     * Flushes the page manager. This forces a flush of all outstanding
+     * blocks (this is an implicit {@link RecordFile#commit} as well).
+     * 
+     * @TODO completely wrong description of method
+     */
+    void rollback() throws IOException 
+    {
+        // release header
+        recordFile.discard( headerBuf );
+        recordFile.rollback();
+        // and obtain it again
+        headerBuf = recordFile.get( 0 );
+        
+        if ( headerBuf.readShort( 0 ) == 0 )
+        {
+            header = new FileHeader( headerBuf, true );
+        }
+        else
+        {
+            header = new FileHeader( headerBuf, false );
+        }
+    }
+    
+    
+    /**
+     * Closes the page manager. This flushes the page manager and releases
+     * the lock on the header.
+     */
+    void close() throws IOException 
+    {   
+        recordFile.release( headerBuf );
+        recordFile.commit();
+        headerBuf = null;
+        header = null;
+        recordFile = null;
+    }
+    
+    
+    /**
+     *  Returns the recordFile header.
+     */
+    FileHeader getFileHeader() 
+    {
+        return header;
+    }    
+    
+    RecordFile getRecordFile()
+    {
+        return recordFile;
+    }
+}
\ No newline at end of file

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PhysicalRowId.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PhysicalRowId.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PhysicalRowId.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PhysicalRowId.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,106 @@
+/**
+ * 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: PhysicalRowId.java,v 1.1 2000/05/06 00:00:31 boisvert Exp $
+ */
+package jdbm.recman;
+
+
+/**
+ * A physical rowid is nothing else than a pointer to a physical location
+ * in a file - a (block, offset) tuple.
+ * <P>
+ * <B>Note</B>: The fact that the offset is modeled as a short limits 
+ * the block size to 32k.
+ */
+class PhysicalRowId 
+{
+    // offsets
+    private static final short O_BLOCK = 0; // long block
+    private static final short O_OFFSET = Magic.SZ_LONG; // short offset
+    static final int SIZE = O_OFFSET + Magic.SZ_SHORT;
+    
+    // my block and the position within the block
+    BlockIo block;
+    short pos;
+
+    
+    /**
+     * Constructs a physical rowid from the indicated data starting at the 
+     * indicated position.
+     */
+    PhysicalRowId( BlockIo block, short pos ) 
+    {
+        this.block = block;
+        this.pos = pos;
+    }
+    
+    
+    /** Returns the block number */
+    long getBlock() 
+    {
+        return block.readLong( pos + O_BLOCK );
+    }
+    
+    
+    /** Sets the block number */
+    void setBlock( long value ) 
+    {
+        block.writeLong( pos + O_BLOCK, value );
+    }
+    
+    
+    /** Returns the offset */
+    short getOffset() 
+    {
+        return block.readShort( pos + O_OFFSET );
+    }
+    
+    
+    /** Sets the offset */
+    void setOffset( short value ) 
+    {
+        block.writeShort( pos + O_OFFSET, value );
+    }
+}
\ No newline at end of file

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PhysicalRowIdManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PhysicalRowIdManager.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PhysicalRowIdManager.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/PhysicalRowIdManager.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,389 @@
+/**
+ * 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: PhysicalRowIdManager.java,v 1.3 2003/03/21 03:00:09 boisvert Exp $
+ */
+package jdbm.recman;
+
+
+import java.io.IOException;
+
+
+/**
+ * This class manages physical row ids, and their data.
+ */
+final class PhysicalRowIdManager
+{
+    /** The file we're talking to and the associated page manager. */
+    private RecordFile file;
+    
+    /** The page manager */
+    private PageManager pageManager;
+    
+    /** The FreePage manager */
+    private FreePhysicalRowIdPageManager freePageManager;
+
+    /**
+     *  Creates a new rowid manager using the indicated record file.
+     *  and page manager.
+     *  @throws IOException If we had an issue while creating the file
+     */
+    PhysicalRowIdManager( PageManager pageManager ) throws IOException
+    {
+        this.pageManager = pageManager;
+        file = pageManager.getRecordFile();
+        freePageManager = new FreePhysicalRowIdPageManager( pageManager );
+    }
+    
+
+    /**
+     *  Inserts a new record. Returns the new physical rowid.
+     */
+    Location insert( byte[] data, int start, int length ) throws IOException
+    {
+        // Find the location for the added data
+        Location retval = alloc( length );
+        
+        // And write it
+        write( retval, data, start, length );
+        
+        return retval;
+    }
+    
+
+    /**
+     *  Updates an existing record. Returns the possibly changed
+     *  physical rowid.
+     */
+    Location update( Location rowid, byte[] data, int start, int length ) throws IOException
+    {
+        // fetch the record header
+        BlockIo block = pageManager.getRecordFile().get( rowid.getBlock() );
+        RecordHeader head = new RecordHeader( block, rowid.getOffset() );
+        
+        if ( length > head.getAvailableSize() ) 
+        {
+            // not enough space - we need to copy to a new rowid.
+            pageManager.getRecordFile().release( block );
+            free( rowid );
+            rowid = alloc( length );
+        } 
+        else 
+        {
+            pageManager.getRecordFile().release( block );
+        }
+
+        // 'nuff space, write it in and return the rowid.
+        write( rowid, data, start, length );
+        
+        return rowid;
+    }
+    
+
+    /**
+     *  Deletes a record.
+     */
+    void delete( Location rowid ) throws IOException
+    {
+        free( rowid );
+    }
+    
+
+    /**
+     *  Retrieves a record.
+     */
+    byte[] fetch( Location rowid ) throws IOException 
+    {
+        // fetch the record header
+        PageCursor curs = new PageCursor( pageManager, rowid.getBlock() );
+        BlockIo block = file.get( curs.getBlockId() );
+        RecordHeader head = new RecordHeader( block, rowid.getOffset() );
+
+        // allocate a return buffer
+        byte[] retval = new byte[ head.getCurrentSize() ];
+        
+        if ( retval.length == 0 ) 
+        {
+            file.release( curs.getBlockId(), false );
+            return retval;
+        }
+
+        // copy bytes in
+        int offsetInBuffer = 0;
+        int leftToRead = retval.length;
+        short dataOffset = (short) (rowid.getOffset() + RecordHeader.SIZE);
+        
+        while ( leftToRead > 0 ) 
+        {
+            // copy current page's data to return buffer
+            int toCopy = RecordFile.BLOCK_SIZE - dataOffset;
+            
+            if ( leftToRead < toCopy ) 
+            {
+                toCopy = leftToRead;
+            }
+            
+            System.arraycopy( block.getData(), dataOffset,
+                              retval, offsetInBuffer,
+                              toCopy );
+
+            // Go to the next block
+            leftToRead -= toCopy;
+            offsetInBuffer += toCopy;
+
+            file.release( block );
+
+            if ( leftToRead > 0 ) 
+            {
+                block = file.get( curs.next() );
+                dataOffset = DataPage.O_DATA;
+            }
+
+        }
+
+        return retval;
+    }
+
+    /**
+     *  Allocate a new rowid with the indicated size.
+     */
+    private Location alloc( int size ) throws IOException
+    {
+        Location retval = freePageManager.get( size );
+        
+        if ( retval == null ) 
+        {
+            // temporary work around for DIRSERVER-1459
+            retval = allocNew( size * 2, pageManager.getLast( Magic.USED_PAGE ) );
+        }
+        
+        return retval;
+    }
+
+    /**
+     *  Allocates a new rowid. The second parameter is there to
+     *  allow for a recursive call - it indicates where the search
+     *  should start.
+     */
+    private Location allocNew( int size, long start ) throws IOException
+    {
+        BlockIo curBlock;
+        DataPage curPage;
+        
+        if ( start == 0 ) 
+        {
+            // we need to create a new page.
+            start = pageManager.allocate( Magic.USED_PAGE );
+            curBlock = file.get( start );
+            curPage = DataPage.getDataPageView( curBlock );
+            curPage.setFirst( DataPage.O_DATA );
+            RecordHeader hdr = new RecordHeader( curBlock, DataPage.O_DATA );
+            hdr.setAvailableSize( 0 );
+            hdr.setCurrentSize( 0 );
+        } 
+        else 
+        {
+            curBlock = file.get( start );
+            curPage = DataPage.getDataPageView( curBlock );
+        }
+
+        // follow the rowids on this page to get to the last one. We don't
+        // fall off, because this is the last page, remember?
+        short pos = curPage.getFirst();
+        
+        if ( pos == 0 ) 
+        {
+            // page is exactly filled by the last block of a record
+            file.release( curBlock );
+            return allocNew( size, 0 );
+        }
+
+        RecordHeader hdr = new RecordHeader( curBlock, pos );
+        
+        while ( hdr.getAvailableSize() != 0 && pos < RecordFile.BLOCK_SIZE ) 
+        {
+            pos += hdr.getAvailableSize() + RecordHeader.SIZE;
+            
+            if ( pos == RecordFile.BLOCK_SIZE ) 
+            {
+                // Again, a filled page.
+                file.release( curBlock );
+                return allocNew( size, 0 );
+            }
+
+            hdr = new RecordHeader( curBlock, pos );
+        }
+
+        if ( pos == RecordHeader.SIZE ) 
+        {
+            // the last record exactly filled the page. Restart forcing
+            // a new page.
+            file.release( curBlock );
+        }
+
+        // we have the position, now tack on extra pages until we've got
+        // enough space.
+        Location retval = new Location( start, pos );
+        int freeHere = RecordFile.BLOCK_SIZE - pos - RecordHeader.SIZE;
+        
+        if ( freeHere < size ) 
+        {
+            // check whether the last page would have only a small bit left.
+            // if yes, increase the allocation. A small bit is a record
+            // header plus 16 bytes.
+            int lastSize = (size - freeHere) % DataPage.DATA_PER_PAGE;
+            
+            if (( DataPage.DATA_PER_PAGE - lastSize ) < (RecordHeader.SIZE + 16) ) 
+            {
+                size += (DataPage.DATA_PER_PAGE - lastSize);
+            }
+
+            // write out the header now so we don't have to come back.
+            hdr.setAvailableSize( size );
+            file.release( start, true );
+
+            int neededLeft = size - freeHere;
+            
+            // Refactor these two blocks!
+            while ( neededLeft >= DataPage.DATA_PER_PAGE ) 
+            {
+                start = pageManager.allocate( Magic.USED_PAGE );
+                curBlock = file.get( start );
+                curPage = DataPage.getDataPageView( curBlock );
+                curPage.setFirst( (short) 0 ); // no rowids, just data
+                file.release( start, true );
+                neededLeft -= DataPage.DATA_PER_PAGE;
+            }
+            
+            if ( neededLeft > 0 ) 
+            {
+                // done with whole chunks, allocate last fragment.
+                start = pageManager.allocate( Magic.USED_PAGE );
+                curBlock = file.get( start );
+                curPage = DataPage.getDataPageView( curBlock );
+                curPage.setFirst( (short) (DataPage.O_DATA + neededLeft) );
+                file.release( start, true );
+            }
+        } else 
+        {
+            // just update the current page. If there's less than 16 bytes
+            // left, we increase the allocation (16 bytes is an arbitrary
+            // number).
+            if ( freeHere - size <= (16 + RecordHeader.SIZE) ) 
+            {
+                size = freeHere;
+            }
+            
+            hdr.setAvailableSize( size );
+            file.release( start, true );
+        }
+        
+        return retval;
+    }
+
+
+    private void free( Location id ) throws IOException
+    {
+        // get the rowid, and write a zero current size into it.
+        BlockIo curBlock = file.get( id.getBlock() );
+        RecordHeader hdr = new RecordHeader( curBlock, id.getOffset() );
+        hdr.setCurrentSize( 0 );
+        file.release( id.getBlock(), true );
+
+        // write the rowid to the free list
+        freePageManager.put( id, hdr.getAvailableSize() );
+    }
+    
+
+    /**
+     *  Writes out data to a rowid. Assumes that any resizing has been
+     *  done.
+     */
+    private void write(Location rowid, byte[] data, int start, int length )
+        throws IOException
+    {
+        PageCursor curs = new PageCursor( pageManager, rowid.getBlock() );
+        BlockIo block = file.get( curs.getBlockId() );
+        RecordHeader hdr = new RecordHeader( block, rowid.getOffset() );
+        hdr.setCurrentSize( length );
+        
+        if ( length == 0 ) 
+        {
+            file.release( curs.getBlockId(), true );
+            
+            return;
+        }
+
+        // copy bytes in
+        int offsetInBuffer = start;
+        int leftToWrite = length;
+        short dataOffset = (short) (rowid.getOffset() + RecordHeader.SIZE);
+        
+        while ( leftToWrite > 0 ) 
+        {
+            // copy current page's data to return buffer
+            int toCopy = RecordFile.BLOCK_SIZE - dataOffset;
+
+            if ( leftToWrite < toCopy ) 
+            {
+                toCopy = leftToWrite;
+            }
+            
+            System.arraycopy( data, offsetInBuffer, block.getData(), dataOffset, toCopy );
+
+            // Go to the next block
+            leftToWrite -= toCopy;
+            offsetInBuffer += toCopy;
+
+            file.release( curs.getBlockId(), true );
+
+            if ( leftToWrite > 0 ) 
+            {
+                block = file.get( curs.next() );
+                dataOffset = DataPage.O_DATA;
+            }
+        }
+    }
+}
+

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Provider.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Provider.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Provider.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/Provider.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,115 @@
+/**
+ * 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.
+ * Copyright 2000-2001 (C) Alex Boisvert. All Rights Reserved.
+ * Contributions are Copyright (C) 2000 by their associated contributors.
+ *
+ * $Id: Provider.java,v 1.3 2005/06/25 23:12:32 doomdark Exp $
+ */
+
+package jdbm.recman;
+
+import java.io.IOException;
+import java.util.Properties;
+
+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.
+ *
+ * @author <a href="mailto:boisvert@intalio.com">Alex Boisvert</a>
+ */
+public final class Provider implements RecordManagerProvider
+{
+    /**
+     * Create a default implementation record manager.
+     *
+     * @param name Name of the record file.
+     * @param options Record manager options.
+     * @throws IOException if an I/O related exception occurs while creating
+     *                    or opening the record manager.
+     * @throws UnsupportedOperationException if some options are not supported by the
+     *                                      implementation.
+     * @throws IllegalArgumentException if some options are invalid.
+     */
+    public RecordManager createRecordManager( String name, Properties options ) throws IOException
+    {
+        RecordManager recman = new BaseRecordManager( name );
+
+        String value = options.getProperty( RecordManagerOptions.DISABLE_TRANSACTIONS, "false" );
+        
+        if ( value.equalsIgnoreCase( "TRUE" ) ) 
+        {
+            ( ( BaseRecordManager ) recman ).disableTransactions();
+        }
+
+        value = options.getProperty( RecordManagerOptions.CACHE_SIZE, "1000" );
+        int cacheSize = Integer.parseInt( value );
+
+        value = options.getProperty( RecordManagerOptions.CACHE_TYPE, RecordManagerOptions.NORMAL_CACHE );
+        
+        if ( value.equalsIgnoreCase( RecordManagerOptions.NORMAL_CACHE ) ) 
+        {
+            MRU cache = new MRU( cacheSize );
+            recman = new CacheRecordManager( recman, cache );
+        } 
+        else if ( value.equalsIgnoreCase( RecordManagerOptions.SOFT_REF_CACHE ) ) 
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_551 ) );
+        } 
+        else if ( value.equalsIgnoreCase( RecordManagerOptions.WEAK_REF_CACHE ) ) 
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_552 ) );
+        } 
+        else 
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_553, value ) );
+        }
+
+        return recman;
+    }
+}

Added: directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/RecordCache.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/RecordCache.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/RecordCache.java (added)
+++ directory/apacheds/trunk/jdbm2/src/main/java/jdbm/recman/RecordCache.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,80 @@
+/**
+ * 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: RecordCache.java,v 1.2 2005/06/25 23:12:32 doomdark Exp $
+ */
+
+package jdbm.recman;
+
+import java.io.IOException;
+
+/**
+ *  This interface is used for synchronization.
+ *  <p>
+ *  RecordManager ensures that the cache has the up-to-date information
+ *  by way of an invalidation protocol.
+ */
+public interface RecordCache {
+
+    /**
+     * Notification to flush content related to a given record.
+     */
+    public void flush(long recid) throws IOException;
+
+    /**
+     * Notification to flush data all of records.
+     */
+    public void flushAll() throws IOException;
+
+    /**
+     * Notification to invalidate content related to given record.
+     */
+    public void invalidate(long recid) throws IOException;
+
+    /**
+     * Notification to invalidate content of all records.
+     */
+    public void invalidateAll() throws IOException;
+
+}