directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From seelm...@apache.org
Subject svn commit: r1164667 [3/6] - in /directory/apacheds/branches/one-sub-level-index-removal: ./ all/ core-annotations/ core-annotations/src/test/java/org/apache/directory/server/core/factory/ core-api/ core-api/src/main/java/org/apache/directory/server/co...
Date Fri, 02 Sep 2011 18:31:02 GMT
Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/btree/BTree.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/btree/BTree.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/btree/BTree.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/btree/BTree.java Fri Sep  2 18:30:57 2011
@@ -47,18 +47,27 @@
 package jdbm.btree;
 
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.Externalizable;
 import java.io.IOException;
 import java.io.ObjectInput;
+import java.io.ObjectInputStream;
 import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.util.Comparator;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
+import jdbm.ActionRecordManager;
 import jdbm.RecordManager;
+import jdbm.helper.ActionContext;
 import jdbm.helper.Serializer;
 import jdbm.helper.Tuple;
 import jdbm.helper.TupleBrowser;
+import jdbm.helper.WrappedRuntimeException;
 
 import org.apache.directory.server.i18n.I18n;
 
@@ -77,7 +86,6 @@ import org.apache.directory.server.i18n.
  * user is responsible to supply a serializable <code>Comparator</code> object
  * to be used for the ordering of entries, which are also called <code>Tuple</code>.
  * The B+Tree allows traversing the keys in forward and reverse order using a
- * TupleBrowser obtained from the browse() methods.
  * <p>
  * This implementation does not directly support duplicate keys, but it is
  * possible to handle duplicates by inlining or referencing an object collection
@@ -106,7 +114,7 @@ public class BTree<K, V> implements Exte
     private transient long recordId;
 
     /** Comparator used to index entries. */
-    private Comparator<K> comparator;
+    Comparator<K> comparator;
 
     /** Serializer used to serialize index keys (optional) */
     protected Serializer keySerializer;
@@ -118,10 +126,10 @@ public class BTree<K, V> implements Exte
      * Height of the B+Tree.  This is the number of BPages you have to traverse
      * to get to a leaf BPage, starting from the root.
      */
-    private int bTreeHeight;
+    int bTreeHeight;
 
     /** Record id of the root BPage */
-    private transient long rootId;
+    private long rootId;
 
     /** Number of entries in each BPage. */
     protected int pageSize;
@@ -131,7 +139,16 @@ public class BTree<K, V> implements Exte
 
     /** Serializer used for BPages of this tree */
     private transient BPage<K, V> bpageSerializer;
-
+    
+    /** TRUE if underlying record manager is snapshot capable */
+    private transient boolean isActionCapable;
+    
+    
+    /** Big lock snychronizing all actions */
+    private transient Lock bigLock = new ReentrantLock(); 
+    
+    /** Meta root used to access versions of Btree root */
+    private transient MetaRoot metaRoot = new MetaRoot();
 
     /**
      * No-argument constructor used by serialization.
@@ -220,8 +237,27 @@ public class BTree<K, V> implements Exte
         this.bpageSerializer = new BPage<K, V>();
         this.bpageSerializer.btree = this;
         this.nbEntries = new AtomicInteger( 0 );
+        
+        this.isActionCapable = recordManager instanceof ActionRecordManager; 
 
-        this.recordId = recordManager.insert( this );
+        boolean abortedAction = false;
+        ActionContext context = this.beginAction( false, "createInstance" );
+        try
+        {
+            this.recordId = recordManager.insert( this );
+            updateMetaRoot( this.rootId, this.bTreeHeight );
+        }
+        catch ( IOException e )
+        {
+            abortedAction = true;
+            this.abortAction( context );
+            throw e;
+        }
+        finally
+        {
+            if ( !abortedAction )
+                this.endAction( context );
+        }
     }
     
     
@@ -246,11 +282,33 @@ public class BTree<K, V> implements Exte
      */
     public BTree<K, V> load( RecordManager recman, long recid ) throws IOException
     {
-        BTree<K, V> btree = (BTree<K, V>) recman.fetch( recid );
-        btree.recordId = recid;
-        btree.recordManager = recman;
-        btree.bpageSerializer = new BPage<K, V>();
-        btree.bpageSerializer.btree = btree;
+        BTree<K, V> btree = null;
+        boolean abortedAction = false;
+        ActionContext context = this.beginAction( false, "load" );
+        
+        try
+        {
+            btree = (BTree<K, V>) recman.fetch( recid );
+            btree.recordId = recid;
+            btree.recordManager = recman;
+            btree.bpageSerializer = new BPage<K, V>();
+            btree.bpageSerializer.btree = btree;
+            btree.updateMetaRoot( btree.rootId, btree.bTreeHeight );
+
+        }
+        catch ( IOException e )
+        {
+            abortedAction = true;
+            this.abortAction( context );
+            throw e;
+        }
+        finally
+        {
+            if ( !abortedAction )
+            {
+                this.endAction( context );
+            }
+        }
         
         return btree;
     }
@@ -268,7 +326,7 @@ public class BTree<K, V> implements Exte
      * @param replace Set to true to replace an existing key-value pair.
      * @return Existing value, if any.
      */
-    public synchronized Object insert( K key, V value, boolean replace ) throws IOException
+    public Object insert( K key, V value, boolean replace ) throws IOException
     {
         if ( key == null )
         {
@@ -280,56 +338,95 @@ public class BTree<K, V> implements Exte
             throw new IllegalArgumentException( I18n.err( I18n.ERR_524 ) );
         }
 
-        BPage<K, V> rootPage = getRoot();
+        
+        boolean abortedAction = false;
+        ActionContext context  = this.beginAction( false, "insert" );
+        
 
-        if ( rootPage == null )
+        if ( !isActionCapable )
         {
-            // BTree is currently empty, create a new root BPage
-            if ( DEBUG )
-            {
-                System.out.println( "BTree.insert() new root BPage" );
-            }
-            
-            rootPage = new BPage<K, V>( this, key, value );
-            rootId = rootPage.getRecordId();
-            bTreeHeight = 1;
-            nbEntries.set( 1 );
-            recordManager.update( recordId, this );
-            
-            return null;
+            bigLock.lock();
         }
-        else
+        
+        try
         {
-            BPage.InsertResult<K, V> insert = rootPage.insert( bTreeHeight, key, value, replace );
-            boolean dirty = false;
-            
-            if ( insert.overflow != null )
+            BPage<K, V> rootPage = getRoot();
+    
+            if ( rootPage == null )
             {
-                // current root page overflowed, we replace with a new root page
+                // BTree is currently empty, create a new root BPage
                 if ( DEBUG )
                 {
-                    System.out.println( "BTree.insert() replace root BPage due to overflow" );
+                    System.out.println( "BTree.insert() new root BPage" );
                 }
                 
-                rootPage = new BPage<K, V>( this, rootPage, insert.overflow );
+                rootPage = new BPage<K, V>( this, key, value );
                 rootId = rootPage.getRecordId();
-                bTreeHeight += 1;
-                dirty = true;
+                bTreeHeight = 1;
+                nbEntries.set( 1 );
+                recordManager.update( recordId, this );
+                updateMetaRoot( this.rootId, this.bTreeHeight );
+                
+                return null;
             }
-            
-            if ( insert.existing == null )
+            else
             {
-                nbEntries.getAndIncrement();
-                dirty = true;
+                BPage.InsertResult<K, V> insert = rootPage.insert( bTreeHeight, key, value, replace );
+                
+                if ( insert.pageNewCopy != null )
+                {
+                    rootPage = insert.pageNewCopy;
+                }
+                
+                boolean dirty = false;
+                
+                if ( insert.overflow != null )
+                {
+                    // current root page overflowed, we replace with a new root page
+                    if ( DEBUG )
+                    {
+                        System.out.println( "BTree.insert() replace root BPage due to overflow" );
+                    }
+                    
+                    rootPage = new BPage<K, V>( this, rootPage, insert.overflow );
+                    rootId = rootPage.getRecordId();
+                    bTreeHeight += 1;
+                    dirty = true;
+                    updateMetaRoot( this.rootId, this.bTreeHeight );
+                }
+                
+                if ( insert.existing == null )
+                {
+                    nbEntries.getAndIncrement();
+                    dirty = true;
+                }
+                
+                if ( dirty )
+                {
+                    recordManager.update( recordId, this );
+                }
+                
+                // insert might have returned an existing value
+                return insert.existing;
             }
-            
-            if ( dirty )
+        }
+        catch ( IOException e )
+        {
+            abortedAction = true;
+            this.abortAction( context );
+            throw e;
+        }
+        finally
+        {
+            if ( !abortedAction )
             {
-                recordManager.update( recordId, this );
+                this.endAction( context );
             }
             
-            // insert might have returned an existing value
-            return insert.existing;
+            if ( !isActionCapable )
+            {
+                bigLock.unlock();
+            }
         }
     }
 
@@ -341,52 +438,88 @@ public class BTree<K, V> implements Exte
      * @return Value associated with the key, or null if no entry with given
      *         key existed in the BTree.
      */
-    public synchronized V remove( K key ) throws IOException
+    public V remove( K key ) throws IOException
     {
         if ( key == null )
         {
             throw new IllegalArgumentException( I18n.err( I18n.ERR_523 ) );
         }
-
-        BPage<K, V> rootPage = getRoot();
+       
         
-        if ( rootPage == null )
+        boolean abortedAction = false;
+        ActionContext context = this.beginAction( false, "remove" );
+
+        if ( !isActionCapable )
         {
-            return null;
+            bigLock.lock();
         }
         
-        boolean dirty = false;
-        BPage.RemoveResult<V> remove = rootPage.remove( bTreeHeight, key );
-        
-        if ( remove.underflow && rootPage.isEmpty() )
+        try
         {
-            bTreeHeight -= 1;
-            dirty = true;
-
-            recordManager.delete( rootId );
+            BPage<K, V> rootPage = getRoot();
             
-            if ( bTreeHeight == 0 )
+            if ( rootPage == null )
             {
-                rootId = 0;
+                return null;
             }
-            else
+            
+            boolean dirty = false;
+            BPage.RemoveResult<K, V> remove = rootPage.remove( bTreeHeight, key );
+            
+            if ( remove.pageNewCopy != null )
             {
-                rootId = rootPage.childBPage( pageSize - 1 ).getRecordId();
+                rootPage = remove.pageNewCopy;
             }
+            
+            if ( remove.underflow && rootPage.isEmpty() )
+            {
+                bTreeHeight -= 1;
+                dirty = true;
+    
+                recordManager.delete( rootId );
+                
+                if ( bTreeHeight == 0 )
+                {
+                    rootId = 0;
+                }
+                else
+                {
+                    rootId = rootPage.childBPage( pageSize - 1 ).getRecordId();
+                }
+                updateMetaRoot( this.rootId, this.bTreeHeight );
+            }
+            
+            if ( remove.value != null )
+            {
+                nbEntries.getAndDecrement();
+                dirty = true;
+            }
+            
+            if ( dirty )
+            {
+                recordManager.update( recordId, this );
+            }
+            
+            return remove.value;
         }
-        
-        if ( remove.value != null )
+        catch ( IOException e )
         {
-            nbEntries.getAndDecrement();
-            dirty = true;
+            abortedAction = true;
+            this.abortAction( context );
+            throw e;
         }
-        
-        if ( dirty )
+        finally
         {
-            recordManager.update( recordId, this );
+            if ( !abortedAction )
+            {
+                this.endAction( context );
+            }
+            
+            if ( !isActionCapable )
+            {
+                bigLock.unlock();
+            }
         }
-        
-        return remove.value;
     }
 
 
@@ -396,40 +529,58 @@ public class BTree<K, V> implements Exte
      * @param key Lookup key.
      * @return Value associated with the key, or null if not found.
      */
-    public synchronized V find( K key ) throws IOException
+    public V find( K key ) throws IOException
     {
+        TupleBrowser<K, V> browser = null;
+        Tuple<K, V> tuple = null;
+        
         if ( key == null )
         {
             throw new IllegalArgumentException( I18n.err( I18n.ERR_523 ) );
         }
         
-        BPage<K, V> rootPage = getRoot();
-        
-        if ( rootPage == null )
+        if ( !isActionCapable )
         {
-            return null;
+            bigLock.lock();
         }
-
-        Tuple<K, V> tuple = new Tuple<K, V>( null, null );
-        TupleBrowser<K, V> browser = rootPage.find( bTreeHeight, key );
-
-        if ( browser.getNext( tuple ) )
-        {
-            // find returns the matching key or the next ordered key, so we must
-            // check if we have an exact match
-            if ( comparator.compare( key, tuple.getKey() ) != 0 )
+        
+        try
+        {      
+            tuple = new Tuple<K, V>( null, null );
+     
+            browser = browse( key );
+   
+            if ( browser.getNext( tuple ) )
             {
-                return null;
+                // find returns the matching key or the next ordered key, so we must
+                // check if we have an exact match
+                if ( comparator.compare( key, tuple.getKey() ) != 0 )
+                {
+                    return null;
+                }
+                else
+                {
+                   return this.copyValue( tuple.getValue() );
+                }
             }
             else
             {
-                return tuple.getValue();
+                return null;
             }
         }
-        else
+        finally
         {
-            return null;
+            if ( browser != null )
+            {
+                browser.close();
+            }
+
+            if ( !isActionCapable )
+            {
+                bigLock.unlock();
+            }
         }
+        
     }
 
 
@@ -441,10 +592,10 @@ public class BTree<K, V> implements Exte
      * @return Value associated with the key, or a greater entry, or null if no
      *         greater entry was found.
      */
-    public synchronized Tuple<K, V> findGreaterOrEqual( K key ) throws IOException
+    public Tuple<K, V> findGreaterOrEqual( K key ) throws IOException
     {
         Tuple<K, V> tuple;
-        TupleBrowser<K, V> browser;
+        TupleBrowser<K, V> browser = null;
 
         if ( key == null )
         {
@@ -453,16 +604,38 @@ public class BTree<K, V> implements Exte
             return null;
         }
 
+        if ( !isActionCapable )
+        { 
+            bigLock.lock();
+        }
+        
         tuple = new Tuple<K, V>( null, null );
-        browser = browse( key );
         
-        if ( browser.getNext( tuple ) )
+        try
         {
-            return tuple;
+            browser = browse( key );
+            
+            if ( browser.getNext( tuple ) )
+            {
+                tuple.setValue( this.copyValue( tuple.getValue() ) );
+                return tuple;
+            }
+            else
+            {
+                return null;
+            }
         }
-        else
+        finally
         {
-            return null;
+            if ( browser != null )
+            {
+                browser.close();
+            }
+            
+            if ( !isActionCapable )
+            {
+                bigLock.unlock();
+            }
         }
     }
 
@@ -476,17 +649,31 @@ public class BTree<K, V> implements Exte
      *
      * @return Browser positionned at the beginning of the BTree.
      */
-    public synchronized TupleBrowser<K, V> browse() throws IOException
+    public TupleBrowser<K, V> browse() throws IOException
     {
-        BPage<K, V> rootPage = getRoot();
+        TupleBrowser<K, V> browser = null;
+        ActionContext context = this.beginAction( true, "browse" );
         
-        if ( rootPage == null )
+        try
         {
-            return new EmptyBrowser(){};
+            MetaRoot meta = this.getMetaRoot();
+            BPage<K, V> rootPage = this.getRoot( meta );
+            
+            if ( rootPage == null )
+            {
+                this.endAction( context );
+                return new EmptyBrowser(){};
+            }
+            
+            browser = rootPage.findFirst( context );
+        }
+        catch( IOException e )
+        {
+            this.abortAction( context );
+            throw e;
         }
         
-        TupleBrowser<K, V> browser = rootPage.findFirst();
-        
+        this.unsetAsCurrentAction( context );
         return browser;
     }
 
@@ -503,19 +690,34 @@ public class BTree<K, V> implements Exte
      *            (Null is considered to be an "infinite" key)
      * @return Browser positioned just before the given key.
      */
-    public synchronized TupleBrowser<K, V> browse( K key ) throws IOException
+    public TupleBrowser<K, V> browse( K key ) throws IOException
     {
-        BPage<K, V> rootPage = getRoot();
+        TupleBrowser<K, V> browser = null;
+        ActionContext context = this.beginAction( true, "browse key" );
         
-        if ( rootPage == null )
+        try
         {
-            return new EmptyBrowser(){};
+            MetaRoot meta = this.getMetaRoot();
+            BPage<K, V> rootPage = this.getRoot( meta );
+            
+            if ( rootPage == null )
+            {
+                this.endAction( context );
+                return new EmptyBrowser(){};
+            }
+          
+            browser  = rootPage.find( meta.treeHeight, key, context );
+        }
+        catch( IOException e )
+        {
+            this.abortAction( context );
+            throw e;
         }
         
-        TupleBrowser<K, V> browser = rootPage.find( bTreeHeight, key );
-        
+        this.unsetAsCurrentAction( context );
         return browser;
     }
+    
 
 
     /**
@@ -537,23 +739,65 @@ public class BTree<K, V> implements Exte
 
 
     /**
-     * Return the root BPage<Object, Object>, or null if it doesn't exist.
+     * @return the root BPage<Object, Object>, or null if it doesn't exist.
+     */
+    BPage<K, V> getRoot( ) throws IOException
+    {        
+        assert( this.rootId == metaRoot.rootID) : "Stale root id " + this.rootId + " "+ metaRoot.rootID;
+        
+        if ( this.rootId == 0 )
+        {
+            return null;
+        }
+        
+        BPage<K, V> root = ( BPage<K, V> ) recordManager.fetch( this.rootId, bpageSerializer );
+        root.setRecordId( this.rootId );
+        root.btree = this;
+        
+        return root;
+    }
+    
+    
+    /**
+     * @param meta The root to search for
+     * 
+     * @return the root BPage<Object, Object>, or null if it doesn't exist.
      */
-    private BPage<K, V> getRoot() throws IOException
+    BPage<K, V> getRoot( MetaRoot meta ) throws IOException
     {
-        if ( rootId == 0 )
+        if ( meta.rootID == 0 )
         {
             return null;
         }
         
-        BPage<K, V> root = ( BPage<K, V> ) recordManager.fetch( rootId, bpageSerializer );
-        root.setRecordId( rootId );
+        BPage<K, V> root = ( BPage<K, V> ) recordManager.fetch( meta.rootID, bpageSerializer );
+        root.setRecordId( meta.rootID );
         root.btree = this;
         
         return root;
     }
-
-
+    
+    
+    /**
+     * 
+     * Returns the meta root that can be used to fetch the root page
+     *
+     * @return meta root The meta root to search for
+     * @throws IOException If we had an exception during the fetch operation
+     */
+    MetaRoot getMetaRoot() throws IOException
+    {
+        if ( isActionCapable )
+        { 
+            return ( MetaRoot )recordManager.fetch( -this.recordId );
+        }
+        else
+        {
+            return metaRoot;
+        }
+    }
+    
+    
     /**
      * Implement Externalizable interface.
      */
@@ -616,6 +860,151 @@ public class BTree<K, V> implements Exte
     }
     
     
+    void setAsCurrentAction( ActionContext context )
+    {
+        if ( context != null )
+        {
+            assert( isActionCapable == true );
+            ( ( ActionRecordManager )recordManager ).setCurrentActionContext( context );
+        }
+    }
+
+    
+    void unsetAsCurrentAction( ActionContext context )
+    {
+        if ( context != null )
+        {
+            assert( isActionCapable == true );
+            ( ( ActionRecordManager )recordManager ).unsetCurrentActionContext( context );
+        }
+    }
+
+    
+    ActionContext beginAction( boolean readOnly, String whoStarted )
+    {
+        ActionContext context = null;
+        
+        if ( isActionCapable )
+        {
+            context = ( ( ActionRecordManager )recordManager ).beginAction( readOnly, whoStarted );
+        }
+        
+        return context;
+    }
+    
+    
+    void endAction( ActionContext context )
+    {
+        if ( context != null )
+        {
+            assert( isActionCapable );
+            ( ( ActionRecordManager )recordManager ).endAction( context );
+        }
+    }
+    
+    
+    void abortAction( ActionContext context )
+    {
+        if ( context != null )
+        {
+            assert( isActionCapable );
+            ( ( ActionRecordManager )recordManager ).abortAction( context );
+        }
+
+    }
+    
+    
+    BPage<K,V> copyOnWrite( BPage<K,V> page) throws IOException
+    {
+       return page.copyOnWrite();
+
+    }
+    
+    
+    private MetaRoot copyOnWrite( MetaRoot oldMetaRoot )
+    {
+        MetaRoot newMetaRoot = new MetaRoot();
+        newMetaRoot.rootID = oldMetaRoot.rootID;
+        newMetaRoot.treeHeight = oldMetaRoot.treeHeight;
+        
+        return newMetaRoot;
+    }
+    
+    
+    private void updateMetaRoot( long newRootId, int newTreeHeight ) throws IOException
+    {
+        metaRoot = this.copyOnWrite( metaRoot );
+        metaRoot.rootID = newRootId;
+        metaRoot.treeHeight = newTreeHeight;
+        
+        if ( isActionCapable )
+        { 
+            recordManager.update( -this.recordId, metaRoot );
+        }
+    }
+    
+    
+    V copyValue( V value) throws IOException 
+    {
+        byte[] array;
+        V valueCopy = null;
+        
+        if ( this.valueSerializer != null )
+        {
+            array = this.valueSerializer.serialize( value );
+            valueCopy = (V) this.valueSerializer.deserialize( array );
+        }
+        else
+        {
+            ObjectOutputStream out = null;
+            ObjectInputStream in = null;
+            ByteArrayOutputStream bout = null;
+            ByteArrayInputStream bin = null;
+
+            try
+            {
+                bout = new ByteArrayOutputStream();
+                out = new ObjectOutputStream( bout );
+                out.writeObject( value );
+                out.flush();
+                byte[]  arr = bout.toByteArray();
+                bin = new ByteArrayInputStream( arr );
+                in =new ObjectInputStream( bin );
+                valueCopy = ( V )in.readObject();
+            }
+            catch ( ClassNotFoundException e )
+            {
+                throw new WrappedRuntimeException( e );
+            }
+            finally
+            {
+                if ( bout != null )
+                {
+                    bout.close();
+                }
+
+                if ( out != null )
+                {
+                    out.close();
+                }
+
+                if ( bin != null )
+                {
+                    bin.close();
+                }
+
+                if ( in != null )
+                {
+                    in.close();
+                }
+            }
+
+        }
+        
+        return valueCopy;
+    }
+    
+    
     public String toString()
     {
         StringBuilder sb = new StringBuilder();
@@ -662,4 +1051,14 @@ public class BTree<K, V> implements Exte
 
         return sb.toString();
     }
+    
+    /**
+     * Used to point to the root page that the reader needs based on the reader's
+     * read action context. ReadWrite actions always use the latest root. 
+     */
+    class MetaRoot
+    {
+        long rootID;
+        int treeHeight;
+    }
 }

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/helper/TupleBrowser.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/helper/TupleBrowser.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/helper/TupleBrowser.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/helper/TupleBrowser.java Fri Sep  2 18:30:57 2011
@@ -73,4 +73,11 @@ public abstract class TupleBrowser<K, V>
      *         no previous tuple.
      */
     public abstract boolean getPrevious( Tuple<K, V> tuple ) throws IOException;
+    
+    
+    /**
+     * Closes the browser and deallocates any resources it might have allocated.
+     * Repeated calls of close are OK.
+     */
+    public void close() {}
 }

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java Fri Sep  2 18:30:57 2011
@@ -49,15 +49,18 @@
 package jdbm.recman;
 
 import java.io.IOException;
-
 import java.util.HashMap;
 import java.util.Map;
-
-import org.apache.directory.server.i18n.I18n;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 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
@@ -81,10 +84,8 @@ import jdbm.helper.DefaultSerializer;
  * @author <a href="mailto:boisvert@intalio.com">Alex Boisvert</a>
  * @author <a href="cg@cdegroot.com">Cees de Groot</a>
  */
-public final class BaseRecordManager
-    implements RecordManager
+public final class BaseRecordManager implements RecordManager
 {
-
     /** Underlying record recordFile. */
     private RecordFile recordFile;
 
@@ -109,6 +110,102 @@ public final class BaseRecordManager
      * the NAME_DIRECTORY_ROOT.
      */
     private Map<String,Long> nameDirectory;
+    
+    private static enum IOType
+    {
+        READ_IO,
+        WRITE_IO
+    }
+
+    /** TODO add asserts to check internal consistency */
+    private static class LockElement
+    {
+        private int readers;
+        private int waiters;
+        private boolean writer;
+
+        private Lock lock = new ReentrantLock();
+        private Condition cv = lock.newCondition();
+
+
+        public boolean anyReaders()
+        {
+            return readers > 0;
+        }
+
+
+        public boolean anyWaiters()
+        {
+            return waiters > 0;
+        }
+
+
+        public boolean beingWritten()
+        {
+            return writer;
+        }
+
+
+        public boolean anyUser()
+        {
+            return ( readers > 0 || waiters > 0 || writer );
+        }
+
+
+        public void bumpReaders()
+        {
+            readers++;
+        }
+
+
+        public void decrementReaders()
+        {
+            readers--;
+        }
+
+
+        public void bumpWaiters()
+        {
+            waiters++;
+        }
+
+
+        public void decrementWaiters()
+        {
+            waiters--;
+        }
+
+
+        public void setWritten()
+        {
+            writer = true;
+        }
+
+
+        public void unsetWritten()
+        {
+            writer = false;
+        }
+
+
+        public Lock getLock()
+        {
+            return lock;
+        }
+
+
+        public Condition getNoConflictingIOCondition()
+        {
+            return cv;
+        }
+    }
+
+    
+    /**
+     * Map used to synchronize reads and writes on the same logical
+     * recid.
+     */
+    private final ConcurrentHashMap<Long, LockElement> lockElements;
 
 
     /**
@@ -123,13 +220,14 @@ public final class BaseRecordManager
         pageMgr = new PageManager( recordFile );
         physMgr = new PhysicalRowIdManager( pageMgr );
         logMgr = new LogicalRowIdManager( pageMgr );
+        lockElements = new ConcurrentHashMap<Long, LockElement>();
     }
 
 
     /**
      * Get the underlying Transaction Manager
      */
-    public synchronized TransactionManager getTransactionManager() throws IOException
+    public TransactionManager getTransactionManager() throws IOException
     {
         checkIfClosed();
         return recordFile.getTxnMgr();
@@ -145,7 +243,7 @@ public final class BaseRecordManager
      *  Only call this method directly after opening the file, otherwise
      *  the results will be undefined.
      */
-    public synchronized void disableTransactions()
+    public void disableTransactions()
     {
         checkIfClosed();
         recordFile.disableTransactions();
@@ -157,7 +255,7 @@ public final class BaseRecordManager
      *
      * @throws IOException when one of the underlying I/O operations fails.
      */
-    public synchronized void close() throws IOException
+    public void close() throws IOException
     {
         checkIfClosed();
 
@@ -190,7 +288,7 @@ public final class BaseRecordManager
      * @return the rowid for the new record.
      * @throws IOException when one of the underlying I/O operations fails.
      */
-    public synchronized long insert( Object obj, Serializer serializer ) throws IOException
+    public long insert( Object obj, Serializer serializer ) throws IOException
     {
         byte[]    data;
         long      recid;
@@ -217,8 +315,9 @@ public final class BaseRecordManager
      * @param recid the rowid for the record that should be deleted.
      * @throws IOException when one of the underlying I/O operations fails.
      */
-    public synchronized void delete( long recid ) throws IOException
+    public void delete( long recid ) throws IOException
     {
+        LockElement element;
         checkIfClosed();
         
         if ( recid <= 0 ) 
@@ -231,10 +330,20 @@ public final class BaseRecordManager
             System.out.println( "BaseRecordManager.delete() recid " + recid ) ;
         }
 
-        Location logRowId = new Location( recid );
-        Location physRowId = logMgr.fetch( logRowId );
-        physMgr.delete( physRowId );
-        logMgr.delete( logRowId );
+        
+        element = this.beginIO(recid, IOType.WRITE_IO);
+        
+        try
+        {
+            Location logRowId = new Location( recid );
+            Location physRowId = logMgr.fetch( logRowId );
+            physMgr.delete( physRowId );
+            logMgr.delete( logRowId );
+        }
+        finally
+        {
+            this.endIO(recid, element, IOType.WRITE_IO);
+        }
     }
 
 
@@ -249,8 +358,8 @@ public final class BaseRecordManager
     {
         update( recid, obj, DefaultSerializer.INSTANCE );
     }
-
     
+
     /**
      * Updates a record using a custom serializer.
      *
@@ -259,8 +368,10 @@ public final class BaseRecordManager
      * @param serializer a custom serializer
      * @throws IOException when one of the underlying I/O operations fails.
      */
-    public synchronized void update( long recid, Object obj, Serializer serializer ) throws IOException
+    public void update( long recid, Object obj, Serializer serializer ) throws IOException
     {
+        LockElement element;
+        
         checkIfClosed();
 
         if ( recid <= 0 ) 
@@ -268,24 +379,33 @@ public final class BaseRecordManager
             throw new IllegalArgumentException( I18n.err( I18n.ERR_536, recid ) );
         }
 
-        Location logRecid = new Location( recid );
-        Location physRecid = logMgr.fetch( logRecid );
-
-        byte[] data = serializer.serialize( obj );
-        
-        if ( DEBUG ) 
-        {
-            System.out.println( "BaseRecordManager.update() recid " + recid + " length " + data.length ) ;
-        }
-        
-        Location newRecid = physMgr.update( physRecid, data, 0, data.length );
-        
-        if ( ! newRecid.equals( physRecid ) ) 
-        {
-            logMgr.update( logRecid, newRecid );
-        }
+        element = this.beginIO(recid, IOType.WRITE_IO);
+         
+        try
+        {
+            Location logRecid = new Location( recid );
+            Location physRecid = logMgr.fetch( logRecid );
+
+            byte[] data = serializer.serialize( obj );
+            
+            if ( DEBUG ) 
+            {
+                System.out.println( "BaseRecordManager.update() recid " + recid + " length " + data.length ) ;
+            }
+            
+            Location newRecid = physMgr.update( physRecid, data, 0, data.length );
+            
+            if ( ! newRecid.equals( physRecid ) ) 
+            {
+                logMgr.update( logRecid, newRecid );
+            }
+         }
+         finally
+         {
+             this.endIO(recid, element, IOType.WRITE_IO);
+         } 
     }
-
+    
 
     /**
      * Fetches a record using standard java object serialization.
@@ -299,7 +419,7 @@ public final class BaseRecordManager
         return fetch( recid, DefaultSerializer.INSTANCE );
     }
 
-
+    
     /**
      * Fetches a record using a custom serializer.
      *
@@ -308,25 +428,40 @@ public final class BaseRecordManager
      * @return the object contained in the record.
      * @throws IOException when one of the underlying I/O operations fails.
      */
-    public synchronized Object fetch( long recid, Serializer serializer )
-        throws IOException
+    public Object fetch( long recid, Serializer serializer ) throws IOException
     {
-        byte[] data;
-
+        Object result;
+        LockElement element;
+        
         checkIfClosed();
-       
+        
         if ( recid <= 0 ) 
         {
             throw new IllegalArgumentException( I18n.err( I18n.ERR_536, recid ) );
         }
         
-        data = physMgr.fetch( logMgr.fetch( new Location( recid ) ) );
+        element = this.beginIO(recid, IOType.READ_IO);
         
-        if ( DEBUG ) 
+        try
+        {
+            byte[] data; 
+            
+            data = physMgr.fetch( logMgr.fetch( new Location( recid ) ) );
+            
+            if ( DEBUG ) 
+            {
+                System.out.println( "BaseRecordManager.fetch() recid " + recid + " length " + data.length ) ;
+            }
+            
+            result = serializer.deserialize( data );
+        }
+        finally
         {
-            System.out.println( "BaseRecordManager.fetch() recid " + recid + " length " + data.length ) ;
+            this.endIO(recid, element, IOType.READ_IO);
         }
-        return serializer.deserialize( data );
+        
+        
+        return result;
     }
 
 
@@ -347,7 +482,7 @@ public final class BaseRecordManager
      *
      *  @see #getRootCount
      */
-    public synchronized long getRoot( int id ) throws IOException
+    public long getRoot( int id ) throws IOException
     {
         checkIfClosed();
 
@@ -360,7 +495,7 @@ public final class BaseRecordManager
      *
      *  @see #getRootCount
      */
-    public synchronized void setRoot( int id, long rowid ) throws IOException
+    public void setRoot( int id, long rowid ) throws IOException
     {
         checkIfClosed();
 
@@ -404,6 +539,7 @@ public final class BaseRecordManager
         {
             getNameDirectory().put( name, recid );
         }
+        
         saveNameDirectory( );
     }
 
@@ -411,8 +547,7 @@ public final class BaseRecordManager
     /**
      * Commit (make persistent) all changes since beginning of transaction.
      */
-    public synchronized void commit()
-        throws IOException
+    public void commit() throws IOException
     {
         checkIfClosed();
 
@@ -423,7 +558,7 @@ public final class BaseRecordManager
     /**
      * Rollback (cancel) all changes since beginning of transaction.
      */
-    public synchronized void rollback() throws IOException
+    public void rollback() throws IOException
     {
         checkIfClosed();
 
@@ -478,4 +613,163 @@ public final class BaseRecordManager
             throw new IllegalStateException( I18n.err( I18n.ERR_538 ) );
         }
     }
+    
+
+    /**
+     * Used to serialize reads/write on a given logical rowid. Checks if there is a 
+     * ongoing conflicting IO to the same logical rowid and waits for the ongoing
+     * write if there is one. 
+     *
+     * @param recid the logical rowid for which the fetch will be done.
+     * @param io type of the IO
+     * @return lock element representing the logical lock gotten
+     */
+    private LockElement beginIO( Long recid, IOType io )
+    {
+        boolean lockVerified = false;
+        LockElement element = null;
+
+        // loop until we successfully verify that there is no concurrent writer
+/*
+        element = lockElements.get( recid );
+        
+        do
+        {
+            if ( element == null )
+            {
+                element = new LockElement();
+
+                if ( io == IOType.READ_IO )
+                {
+                    element.bumpReaders();
+                }
+                else
+                {
+                    element.setWritten();
+                }
+
+                LockElement existingElement = lockElements.putIfAbsent( recid, element );
+
+                if ( existingElement == null )
+                {
+                    lockVerified = true;
+                }
+                else
+                {
+                    element = existingElement;
+                }
+            }
+            else
+            {
+                Lock lock = element.getLock();
+                lock.lock();
+                
+                if ( element.anyUser() )
+                {
+                    if ( this.conflictingIOPredicate( io, element ) )
+                    {
+                        element.bumpWaiters();
+                        
+                        do
+                        {
+                            element.getNoConflictingIOCondition()
+                                .awaitUninterruptibly();
+                        }
+                        while ( this.conflictingIOPredicate( io, element ) );
+
+                        element.decrementWaiters();
+                    }
+
+                    // no conflicting IO anymore..done
+                    if ( io == IOType.READ_IO )
+                    {
+                        element.bumpReaders();
+                    }
+                    else
+                    {
+                        element.setWritten();
+                    }
+                    
+                    lockVerified = true;
+                }
+                else
+                {
+                    if ( io == IOType.READ_IO )
+                    {
+                        element.bumpReaders();
+                    }
+                    else
+                    {
+                        element.setWritten();
+                    }
+
+                    LockElement existingElement = lockElements.get( recid );
+
+                    if ( element != existingElement )
+                    {
+                        element = existingElement;
+                    }
+                    else
+                    {
+                        lockVerified = true; // done
+                    }
+                }
+                
+                lock.unlock();
+            }
+        }
+        while ( !lockVerified );
+*/
+        return element;
+    }
+
+
+    /**
+     * Ends the IO by releasing the logical lock on the given recid
+     * 
+     * @param recid logical recid for which the IO is being ended
+     * @param element logical lock to be released
+     * @param io type of the io
+     */
+    private void endIO( Long recid, LockElement element, IOType io )
+    {
+        /*
+        Lock lock = element.getLock();
+        lock.lock();
+
+        if ( io == IOType.READ_IO )
+        {
+            element.decrementReaders();
+        }
+        else
+        {
+            element.unsetWritten();
+        }
+
+        if ( element.anyWaiters() )
+        {
+            element.getNoConflictingIOCondition().notifyAll();
+        }
+
+        if ( !element.anyUser() )
+        {
+            lockElements.remove( recid );
+        }
+
+        lock.unlock();
+        */
+    }
+
+
+    private boolean conflictingIOPredicate( IOType io, LockElement element )
+    {
+        if ( io == IOType.READ_IO )
+        { 
+            return element.beingWritten();
+        }
+        else
+        {
+            return ( element.anyReaders() || element.beingWritten() );
+        }
+    }
 }

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/BlockIo.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/BlockIo.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/BlockIo.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/BlockIo.java Fri Sep  2 18:30:57 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 <ejb@klomp.org>
-        // Gives about 15% performance improvement
         return
-            ( ( long )( ( ( data[pos+0] & 0xff ) << 24 ) |
-                        ( ( data[pos+1] & 0xff ) << 16 ) |
-                        ( ( data[pos+2] & 0xff ) <<  8 ) |
-                        ( ( data[pos+3] & 0xff )       ) ) << 32 ) |
-            ( ( long )( ( ( data[pos+4] & 0xff ) << 24 ) |
-                        ( ( data[pos+5] & 0xff ) << 16 ) |
-                        ( ( data[pos+6] & 0xff ) <<  8 ) |
-                        ( ( data[pos+7] & 0xff )       ) ) & 0xffffffff );
+            ( ( 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,23 +355,59 @@ 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 ( "
-            + blockId + ", "
-            + dirty   + ", "
-            + view    + " )";
+        if ( view != null )
+        {
+            return view.toString();
+        }
+        
+        StringBuilder sb = new StringBuilder();
+        
+        sb.append( "BlockIO ( " );
+        
+        // The blockID
+        sb.append( blockId ).append( ", " );
+        
+        // Is it dirty ?
+        if ( dirty )
+        {
+            sb.append( "dirty, " );
+        }
+        else
+        {
+            sb.append( "clean, " );
+        }
+        
+        // The view
+        if ( view != null )
+        {
+            sb.append( view.getClass().getSimpleName() ).append( ", " );
+        }
+        else
+        {
+            sb.append( "no view, " );
+        }
+        
+        // The transaction count
+        sb.append( "tx: " ).append( transactionCount.get() );
+
+        sb.append( " )" );
+        
+        return sb.toString();
     }
 
     
-    // implement externalizable interface
-    
+    /**
+     * implement externalizable interface
+     */
     public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException 
     {
         blockId = in.readLong();
@@ -359,7 +417,9 @@ public final class BlockIo implements ja
     }
 
     
-    // implement externalizable interface
+    /**
+     * implement externalizable interface
+     */
     public void writeExternal( ObjectOutput out ) throws IOException 
     {
         out.writeLong( blockId );

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/DataPage.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/DataPage.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/DataPage.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/DataPage.java Fri Sep  2 18:30:57 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,36 +79,67 @@ 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 );
+        return blockIo.readShort( O_FIRST );
     }
     
     
-    /** Sets the first rowid's offset */
+    /** 
+     * Sets the first rowid's offset 
+     */
     void setFirst( short value ) 
     {
         paranoiaMagicOk();
+        
         if ( value > 0 && value < O_DATA )
         {
             throw new Error( I18n.err( I18n.ERR_543, value ) );
         }
   
-        block.writeShort( O_FIRST, value );
+        blockIo.writeShort( O_FIRST, value );
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() 
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        sb.append( "DataPage ( " );
+        
+        // The blockIO
+        sb.append( super.toString() ).append( ", " );
+        
+        // The first rowId
+        sb.append( "first rowId: " ).append( getFirst() ).append( ", " );
+        
+        // The data per page 
+        sb.append( "[p:" ).append( getPrev() ).append( ", " );
+        
+        // The next page
+        sb.append( "n:" ).append( getNext() ).append( "] )" );
+        
+        return sb.toString();
     }
 }

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPage.java Fri Sep  2 18:30:57 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,107 +56,187 @@ 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
+    
+    /** Offset of the number of free row Ids */
     static final short O_FREE = O_COUNT + Magic.SZ_SHORT;
+    
+    /** The number of elements by page */
     static final short ELEMS_PER_PAGE = ( RecordFile.BLOCK_SIZE - O_FREE ) / PhysicalRowId.SIZE;
 
-    // slots we returned.
+    /** */
     final PhysicalRowId[] slots = new PhysicalRowId[ELEMS_PER_PAGE];
 
     
     /**
      * Constructs a data page view from the indicated block.
      */
-    FreeLogicalRowIdPage( BlockIo block ) 
+    FreeLogicalRowIdPage( BlockIo blockIo ) 
     {
-        super( block );
+        super( blockIo );
     }
     
 
     /**
      * Factory method to create or return a data page for the indicated block.
      */
-    static FreeLogicalRowIdPage getFreeLogicalRowIdPageView( BlockIo block ) 
+    static FreeLogicalRowIdPage getFreeLogicalRowIdPageView( BlockIo blockIo ) 
     {
-        BlockView view = block.getView();
-        if ( view != null && view instanceof FreeLogicalRowIdPage )
+        BlockView view = blockIo.getView();
+        
+        if ( ( view != null ) && ( view instanceof FreeLogicalRowIdPage ) )
         {
             return ( FreeLogicalRowIdPage ) view;
         }
         else
         {
-            return new FreeLogicalRowIdPage(block);
+            return new FreeLogicalRowIdPage( blockIo );
         }
     }
 
     
-    /** Returns the number of free rowids */
-    short getCount() {
-        return block.readShort(O_COUNT);
+    /** 
+     * @return the number of free rowids 
+     */
+    short getCount() 
+    {
+        return blockIo.readShort( O_COUNT );
     }
+    
 
-    /** Sets the number of free rowids */
-    private void setCount(short i) {
-        block.writeShort(O_COUNT, i);
+    /** 
+     * 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).setBlock(0);
-        setCount((short) (getCount() - 1));
+    /** 
+     * Frees a slot 
+     */
+    void free( int slot ) 
+    {
+        get( slot ).setBlock( 0 );
+        setCount( (short) ( getCount() - 1 ) );
     }
+    
 
-    /** Allocates a slot */
-    PhysicalRowId alloc(int slot) {
-        setCount((short) (getCount() + 1));
-        get(slot).setBlock(-1);
-        return get(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) {
-        return get(slot).getBlock() > 0;
+    /** 
+     * Returns true if a slot is allocated 
+     */
+    private 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 
+     */
+    private boolean isFree( int slot ) 
+    {
         return !isAllocated(slot);
     }
 
 
-    /** Returns the value of the indicated slot */
-    PhysicalRowId get(int slot) {
-        if (slots[slot] == null)
-            slots[slot] = new PhysicalRowId(block, slotToOffset(slot));
+    /** 
+     * Returns the value of the indicated slot 
+     */
+    PhysicalRowId get( int slot ) 
+    {
+        if ( slots[slot] == null )
+        {
+            slots[slot] = new PhysicalRowId( blockIo, 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++) {
-            if (isFree(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.
+     * @return The first allocated slot, -1 if no slots are available.
      */
-    int getFirstAllocated() {
-        for (int i = 0; i < ELEMS_PER_PAGE; i++) {
-            if (isAllocated(i))
+    int getFirstAllocated() 
+    {
+        for ( int i = 0; i < ELEMS_PER_PAGE; i++ ) 
+        {
+            if ( isAllocated( i ) )
+            {
                 return i;
+            }
         }
+        
         return -1;
     }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() 
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        sb.append( "FreeLogRowIdPage ( " );
+        
+        // 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( ">" );
+            }
+        }
+
+        sb.append( ")" );
+
+        return sb.toString();
+    }
 }

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreeLogicalRowIdPageManager.java Fri Sep  2 18:30:57 2011
@@ -53,90 +53,119 @@ 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 {
-    // our record recordFile
+final class FreeLogicalRowIdPageManager 
+{
+    /** our record recordFile */
     private RecordFile recordFile;
-    // our page manager
+    
+    /** our page manager */
     private PageManager pageManager;
 
     /**
      *  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) {
-            FreeLogicalRowIdPage fp = FreeLogicalRowIdPage
-                .getFreeLogicalRowIdPageView(recordFile.get(curs.getCurrent()));
+        // Create a cursor to browse the pages
+        PageCursor cursor = new PageCursor( pageManager, Magic.FREELOGIDS_PAGE );
+        
+        // Loop on the pages now
+        while ( cursor.next() != 0 ) 
+        {
+            // Get the blockIo associated with the blockId
+            BlockIo blockIo = recordFile.get( cursor.getBlockId() );
+            FreeLogicalRowIdPage fp = FreeLogicalRowIdPage.getFreeLogicalRowIdPageView( blockIo );
+            
+            // Get the first allocated FreeLogicalRowId
             int slot = fp.getFirstAllocated();
-            if (slot != -1) {
+            
+            if ( slot != -1 ) 
+            {
                 // got one!
-                retval =
-                    new Location(fp.get(slot));
-                fp.free(slot);
-                if (fp.getCount() == 0) {
+                Location location = new Location( fp.get( slot ) );
+                
+                // Remove the block from the page
+                fp.free( slot );
+                
+                boolean hasMore = fp.getCount() != 0;
+                
+                // Upate the recordFile
+                recordFile.release( cursor.getBlockId(), hasMore );
+
+                if ( !hasMore ) 
+                {
                     // page became empty - free it
-                    recordFile.release(curs.getCurrent(), false);
-                    pageManager.free(Magic.FREELOGIDS_PAGE, curs.getCurrent());
+                    pageManager.free( Magic.FREELOGIDS_PAGE, cursor.getBlockId() );
                 }
-                else
-                    recordFile.release(curs.getCurrent(), true);
                 
-                return retval;
+                return location;
             }
-            else {
+            else 
+            {
                 // no luck, go to next page
-                recordFile.release(curs.getCurrent(), false);
-            }     
+                recordFile.release( cursor.getBlockId(), false );
+            }
         }
+        
         return null;
     }
 
+    
     /**
      *  Puts the indicated rowid on the free list
+     *  
+     *  @param rowId The Location where we will store the rowId
      */
-    void put(Location rowid)
-    throws IOException {
+    void put( Location rowId ) throws IOException 
+    {
         
         PhysicalRowId free = null;
-        PageCursor curs = new PageCursor(pageManager, Magic.FREELOGIDS_PAGE);
+        
+        // Create a cursor on the FREELOGIDs list
+        PageCursor curs = new PageCursor( pageManager, Magic.FREELOGIDS_PAGE );
         long freePage = 0;
-        while (curs.next() != 0) {
-            freePage = curs.getCurrent();
-            BlockIo curBlock = recordFile.get(freePage);
-            FreeLogicalRowIdPage fp = FreeLogicalRowIdPage
-                .getFreeLogicalRowIdPageView(curBlock);
+        
+        // Loop on all the list
+        while ( curs.next() != 0 )
+        {
+            freePage = curs.getBlockId();
+            BlockIo curBlockIo = recordFile.get( freePage );
+            FreeLogicalRowIdPage fp = FreeLogicalRowIdPage.getFreeLogicalRowIdPageView( curBlockIo );
             int slot = fp.getFirstFree();
-            if (slot != -1) {
+            
+            if ( slot != -1 ) 
+            {
                 free = fp.alloc(slot);
                 break;
             }
             
-            recordFile.release(curBlock);
+            recordFile.release( curBlockIo );
         }
-        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);
-            free = fp.alloc(0);
+            freePage = pageManager.allocate( Magic.FREELOGIDS_PAGE );
+            BlockIo curBlockIo = recordFile.get( freePage );
+            FreeLogicalRowIdPage fp = FreeLogicalRowIdPage.getFreeLogicalRowIdPageView( curBlockIo );
+            free = fp.alloc( 0 );
         }
-        free.setBlock(rowid.getBlock());
-        free.setOffset(rowid.getOffset());
-        recordFile.release(freePage, true);
+        
+        free.setBlock( rowId.getBlock() );
+        free.setOffset( rowId.getOffset() );
+        recordFile.release( freePage, true );
     }
-}
+}
\ No newline at end of file

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPage.java Fri Sep  2 18:30:57 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 );
+        return blockIo.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 );
+        blockIo.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,33 +127,41 @@ 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 )
         {
-            slots[slot] = new FreePhysicalRowId( block, slotToOffset( slot ) ) ;
+            slots[slot] = new FreePhysicalRowId( blockIo, slotToOffset( slot ) ) ;
         }
   
         return slots[slot];
     }
     
 
-    /** 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 ) 
@@ -183,4 +201,37 @@ final class FreePhysicalRowIdPage extend
   
         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

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPageManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPageManager.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPageManager.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/FreePhysicalRowIdPageManager.java Fri Sep  2 18:30:57 2011
@@ -87,7 +87,7 @@ final class FreePhysicalRowIdPageManager
         while ( curs.next() != 0 ) 
         {
             FreePhysicalRowIdPage fp = FreePhysicalRowIdPage
-                .getFreePhysicalRowIdPageView( recordFile.get( curs.getCurrent() ) );
+                .getFreePhysicalRowIdPageView( recordFile.get( curs.getBlockId() ) );
             int slot = fp.getFirstLargerThan( size );
             
             if ( slot != -1 ) 
@@ -99,12 +99,12 @@ final class FreePhysicalRowIdPageManager
                 if ( fp.getCount() == 0 ) 
                 {
                     // page became empty - free it
-                    recordFile.release( curs.getCurrent(), false );
-                    pageManager.free( Magic.FREEPHYSIDS_PAGE, curs.getCurrent() );
+                    recordFile.release( curs.getBlockId(), false );
+                    pageManager.free( Magic.FREEPHYSIDS_PAGE, curs.getBlockId() );
                 } 
                 else 
                 {
-                    recordFile.release( curs.getCurrent(), true );
+                    recordFile.release( curs.getBlockId(), true );
                 }
 
                 return retval;
@@ -112,7 +112,7 @@ final class FreePhysicalRowIdPageManager
             else 
             {
                 // no luck, go to next page
-                recordFile.release( curs.getCurrent(), false );
+                recordFile.release( curs.getBlockId(), false );
             }
         }
         return null;
@@ -130,7 +130,7 @@ final class FreePhysicalRowIdPageManager
         
         while ( curs.next() != 0 ) 
         {
-            freePage = curs.getCurrent();
+            freePage = curs.getBlockId();
             BlockIo curBlock = recordFile.get( freePage );
             FreePhysicalRowIdPage fp = FreePhysicalRowIdPage.getFreePhysicalRowIdPageView( curBlock );
             int slot = fp.getFirstFree();

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/Location.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/Location.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/Location.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/Location.java Fri Sep  2 18:30:57 2011
@@ -54,16 +54,22 @@ package jdbm.recman;
  */
 final class Location 
 {
-    private long block;
+    /** 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 block, short offset ) 
+    Location( long blockId, short offset ) 
     {
-        this.block = block;
+        this.blockId = blockId;
         this.offset = offset;
     }
 
@@ -71,30 +77,34 @@ final class Location 
     /**
      * 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.block = blockOffset >> 16;
+        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 src ) 
+    Location( PhysicalRowId physicalRowId ) 
     {
-        block = src.getBlock();
-        offset = src.getOffset();
+        blockId = physicalRowId.getBlock();
+        offset = physicalRowId.getOffset();
     }
 
     
     /**
-     * Returns the file block of the location
+     * @eturn the blockId of the location
      */
     long getBlock() 
     {
-        return block;
+        return blockId;
     }
 
     
@@ -114,7 +124,7 @@ final class Location 
      */
     long toLong() 
     {
-        return ( block << 16 ) + ( long ) offset;
+        return ( blockId << 16 ) + ( long ) offset;
     }
 
     
@@ -133,21 +143,26 @@ final class Location 
     @Override
    public boolean equals( Object o ) 
     {
-        if ( o == null || ! ( o instanceof Location ) )
+        if ( ( o == null ) || ! ( o instanceof Location ) )
         {
             return false;
         }
         
         Location ol = ( Location ) o;
-        return ol.block == block && ol.offset == offset;
+        
+        return ( ol.blockId == blockId ) && ( ol.offset == offset );
     }
 
     
+    /**
+     * {@inheritDoc}
+     */
     public String toString() 
     {
         StringBuilder sb = new StringBuilder();
-        sb.append( "Location ( " ).append( block ).append( " : " );
+        sb.append( "Location ( " ).append( blockId ).append( " : " );
         sb.append( offset ).append( " ) " );
+        
         return sb.toString();
     }
 }

Modified: directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/LogicalRowIdManager.java Fri Sep  2 18:30:57 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/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/PageCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/PageCursor.java?rev=1164667&r1=1164666&r2=1164667&view=diff
==============================================================================
--- directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/PageCursor.java (original)
+++ directory/apacheds/branches/one-sub-level-index-removal/jdbm/src/main/java/jdbm/recman/PageCursor.java Fri Sep  2 18:30:57 2011
@@ -55,65 +55,85 @@ import java.io.IOException;
  */
 final class PageCursor 
 {
-    PageManager pageman;
-    long current;
+    /** 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 pageman, long current ) 
+    PageCursor( PageManager pageManager, long blockId ) 
     {
-        this.pageman = pageman;
-        this.current = current;
+        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 pageman, short type ) throws IOException 
+    PageCursor( PageManager pageManager, short type ) throws IOException 
     {
-        this.pageman = pageman;
+        this.pageManager = pageManager;
         this.type = type;
     }
     
     
     /**
-     * Returns the current value of the cursor.
+     * @return the BlockId
      */
-    long getCurrent() throws IOException 
+    long getBlockId() throws IOException 
     {
-        return current;
+        return blockId;
     }
     
     
     /**
-     * Returns the next value of the cursor.
+     * @return the next blockId 
      */
     long next() throws IOException 
     {
-        if ( current == 0 )
+        if ( blockId == 0 )
         {
-            current = pageman.getFirst( type );
+            blockId = pageManager.getFirst( type );
         }
         else
         {
-            current = pageman.getNext( current );
+            blockId = pageManager.getNext( blockId );
         }
         
-        return current;
+        return blockId;
     } 
     
     
     /**
-     * Returns the previous value of the cursor
+     * @return the previous blockId
      */
     long prev() throws IOException 
     {
-        current = pageman.getPrev( current );
-        return current;
+        blockId = pageManager.getPrev( blockId );
+        
+        return blockId;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return "Location( " + blockId + ", " + type + ")";
     }
 }



Mime
View raw message