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 [9/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/test/java/jdbm/btree/TestBTreeBrowser.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestBTreeBrowser.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestBTreeBrowser.java (added)
+++ directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestBTreeBrowser.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,430 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package jdbm.btree;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import jdbm.RecordManager;
+import jdbm.RecordManagerFactory;
+import jdbm.helper.StringComparator;
+import jdbm.helper.Tuple;
+import jdbm.helper.TupleBrowser;
+import jdbm.recman.SnapshotRecordManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ *  Tests proper function of {@link TupleBrowser} and {@link BPage.Browser}
+ *  when structural changes happen on the BTree.
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TestBTreeBrowser
+{
+    @Rule
+    public TemporaryFolder folder = new TemporaryFolder();
+
+    private RecordManager recordManager;
+    private SnapshotRecordManager snapshotRecman;
+    private BTree<String, String> tree;
+    private Tuple<String, String> tuple;
+
+
+    private String getTemporaryFile( String name ) throws IOException
+    {
+        String file = folder.newFile( name ).getAbsolutePath();
+        return file;
+    }
+
+
+    @Before
+    public void setup() throws IOException
+    {
+        tuple = new Tuple<String, String>();
+        recordManager = RecordManagerFactory.createRecordManager( getTemporaryFile( "testBrowser" ) );
+        snapshotRecman = new SnapshotRecordManager( recordManager, 1 << 12 );
+        tree = new BTree<String, String>( snapshotRecman, new StringComparator() );
+        tree.setPageSize( 4 );
+
+        // insert different objects and retrieve them
+        tree.insert( "test15", "value1", false );
+        tree.insert( "test25", "value2", false );
+        tree.insert( "test35", "value3", false );
+        tree.insert( "test45", "value4", false );
+        tree.insert( "test55", "value5", false );
+        tree.insert( "test65", "value6", false );
+    }
+
+
+    @After
+    public void teardown() throws IOException
+    {
+        recordManager.close();
+    }
+
+
+    /**
+     *  Test the browser.
+     */
+    @Test
+    public void testBrowse() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        int count = 0;
+        while ( browser.getNext( tuple ) )
+        {
+            count++;
+        }
+        assertEquals( 6, count );
+
+        count = 0;
+        while ( browser.getPrevious( tuple ) )
+        {
+            count++;
+        }
+        assertEquals( 6, count );
+    }
+
+
+    @Test
+    public void testBrowseWithRemoveFirstBeforeStart() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        tree.remove( "test15" );
+        tree.remove( "test55" );
+
+        // removed tuples should still be visible
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        tree.remove( "test65" );
+        tree.remove( "test35" );
+
+        // removed tuples should still be visible
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+        assertHasPrevious( browser, "test45", "value4" );
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithInsertFirstBeforeStart() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        tree.insert( "test11", "value1", false );
+        tree.insert( "test59", "value5", false );
+
+        // inserted tuples should not be visible
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        tree.insert( "test29", "value2", false );
+        tree.insert( "test69", "value6", false );
+
+        // inserted tuples should not be visible
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+        assertHasPrevious( browser, "test45", "value4" );
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithRemoveFirstWhileBrowsing() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+
+        tree.remove( "test15" );
+
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+
+        tree.remove( "test65" );
+
+        assertHasPrevious( browser, "test45", "value4" );
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithInsertFirstWhileBrowsing() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+
+        tree.insert( "test11", "value1", false );
+
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+
+        tree.insert( "test69", "value6", false );
+
+        assertHasPrevious( browser, "test45", "value4" );
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithRemovePreviousWhileBrowsing() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+
+        tree.remove( "test35" );
+
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+
+        tree.remove( "test55" );
+
+        assertHasPrevious( browser, "test45", "value4" );
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithInsertPreviousWhileBrowsing() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+
+        tree.insert( "test29", "value2", false );
+
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+
+        tree.insert( "test59", "value5", false );
+
+        assertHasPrevious( browser, "test45", "value4" );
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithRemoveNextWhileBrowsing() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+
+        tree.remove( "test45" );
+
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+        assertHasPrevious( browser, "test45", "value4" );
+
+        tree.remove( "test35" );
+
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithInsertNextWhileBrowsing() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+
+        tree.insert( "test39", "value3", false );
+
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+        assertHasPrevious( browser, "test45", "value4" );
+
+        tree.insert( "test41", "value4", false );
+
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithRemoveLastWhileBrowsing() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+
+        tree.remove( "test65" );
+
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+        assertHasPrevious( browser, "test45", "value4" );
+
+        tree.remove( "test15" );
+
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    @Test
+    public void testBrowseWithInsertLastWhileBrowsing() throws IOException
+    {
+        TupleBrowser<String, String> browser = tree.browse();
+
+        assertHasNext( browser, "test15", "value1" );
+        assertHasNext( browser, "test25", "value2" );
+        assertHasNext( browser, "test35", "value3" );
+
+        tree.insert( "test69", "value6", false );
+
+        assertHasNext( browser, "test45", "value4" );
+        assertHasNext( browser, "test55", "value5" );
+        assertHasNext( browser, "test65", "value6" );
+        assertFalse( browser.getNext( tuple ) );
+
+        assertHasPrevious( browser, "test65", "value6" );
+        assertHasPrevious( browser, "test55", "value5" );
+        assertHasPrevious( browser, "test45", "value4" );
+
+        tree.insert( "test11", "value1", false );
+
+        assertHasPrevious( browser, "test35", "value3" );
+        assertHasPrevious( browser, "test25", "value2" );
+        assertHasPrevious( browser, "test15", "value1" );
+        assertFalse( browser.getPrevious( tuple ) );
+    }
+
+
+    private void assertHasNext( TupleBrowser<String, String> browser, String key, String value ) throws IOException
+    {
+        assertTrue( browser.getNext( tuple ) );
+        assertEquals( key, tuple.getKey() );
+        assertEquals( value, tuple.getValue() );
+    }
+
+
+    private void assertHasPrevious( TupleBrowser<String, String> browser, String key, String value ) throws IOException
+    {
+        assertTrue( browser.getPrevious( tuple ) );
+        assertEquals( key, tuple.getKey() );
+        assertEquals( value, tuple.getValue() );
+    }
+
+}

Added: directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestSnapshotBTree.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestSnapshotBTree.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestSnapshotBTree.java (added)
+++ directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestSnapshotBTree.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,607 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package jdbm.btree;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Random;
+import java.util.concurrent.Semaphore;
+
+import jdbm.RecordManager;
+import jdbm.RecordManagerFactory;
+import jdbm.helper.IntegerComparator;
+import jdbm.helper.Tuple;
+import jdbm.helper.TupleBrowser;
+import jdbm.recman.SnapshotRecordManager;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * 
+ * TODO SnapshotBTree.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class TestSnapshotBTree
+{
+    @Rule
+    public TemporaryFolder folder = new TemporaryFolder();
+    
+    private static class IntWrapper implements Serializable
+    {
+        int value;
+        IntWrapper( int value )
+        {
+            this.value = value;
+        }
+    }
+    
+    private String getTemporaryFile( String name ) throws IOException
+    {
+        String file = folder.newFile( name ).getAbsolutePath();
+        return file;
+    }
+    
+    @Test
+    public void testBasic1() throws IOException, InterruptedException
+    {
+        RecordManager recman;
+        BTree<Integer, IntWrapper> tree;
+      
+        int idx;
+        int numReadThreads = 1;
+        BasicTestThread readThreads[] = new BasicTestThread[numReadThreads];
+        BasicTestThread updateThread;
+        
+        Semaphore browseSem = new Semaphore( 0 );
+        Semaphore updateSem = new Semaphore( 0 );
+
+        recman = RecordManagerFactory.createRecordManager( getTemporaryFile( "testBasic1" ) );
+        SnapshotRecordManager snapshotRecman = new SnapshotRecordManager( recman, 1 << 12 );
+        
+        tree = new BTree<Integer, IntWrapper>( snapshotRecman, new IntegerComparator() );
+     
+        for ( idx = 0; idx < 1024; idx++ )
+        {
+            tree.insert( new Integer( idx ), new IntWrapper( idx ), true );
+        }
+
+        for ( idx = 0; idx < numReadThreads; idx++ )
+        {
+            readThreads[idx] = new BasicTestThread( true, tree, browseSem, updateSem, numReadThreads );
+        }
+        updateThread = new BasicTestThread( false, tree, browseSem, updateSem, numReadThreads );      
+        
+        updateThread.start();
+        
+        for ( idx = 0; idx < numReadThreads; idx++ )
+        {
+            readThreads[idx].start();
+        }
+        
+        for ( idx = 0; idx < numReadThreads; idx++ )
+        {
+            readThreads[idx].join();
+        }
+        updateThread.join();
+        
+        snapshotRecman.close();
+    }
+    
+   
+    
+    
+    class BasicTestThread extends Thread
+    {
+        boolean readOnly;
+        BTree<Integer, IntWrapper> btree;
+        Semaphore browseSem;
+        Semaphore updateSem;
+        int numReadThreads;
+
+        BasicTestThread( boolean readOnly, BTree<Integer, IntWrapper> btree, Semaphore firstBrowse,
+                    Semaphore updateDone, int numReadThreads )
+        {
+            this.readOnly = readOnly;
+            this.btree = btree;
+            this.browseSem = firstBrowse;
+            this.updateSem = updateDone;
+            this.numReadThreads = numReadThreads;
+        }
+
+
+
+        private void readOnlyActions() throws IOException, InterruptedException
+        {
+            int count = 0;
+            int idx;
+            TupleBrowser<Integer, IntWrapper> browser = btree.browse();
+            Tuple<Integer, IntWrapper> tuple = new Tuple();
+            browseSem.release();
+
+            assertTrue( browser.getNext( tuple ) );
+            assertEquals( tuple.getKey().intValue(), 0 );
+            count++;
+
+            assertTrue( browser.getNext( tuple ) );
+            assertEquals( tuple.getKey().intValue(), 1 );
+            count++;
+
+            while( browser.getNext( tuple ) )
+            {
+                count++;
+
+                // Sleep a little randomly.                                                                                                                                                               
+                if ( (count & 7) == 0 )
+                {
+                    Thread.sleep( 1 );
+                }
+                
+                assertTrue( tuple.getValue().value != -1 );
+            }
+
+
+            System.out.println( "count is " + count );
+            assertEquals( count, 1024 );
+            browser.close();
+
+            updateSem.acquireUninterruptibly();
+            browser = btree.browse( new Integer( 10 ) );
+
+            browseSem.release();
+            
+            for ( idx = 20; idx < 1024; idx++ )
+            {
+                assertTrue( browser.getNext( tuple ) );
+
+                //System.out.println( "key:"+ tuple.getKey().intValue() + " idx:" + idx );
+                assertTrue( tuple.getKey().intValue() == idx );
+            }
+            
+            browser.close();
+        }
+        
+        private void readWriteActions() throws IOException
+        {
+            int idx;
+
+            for ( idx = 0; idx < numReadThreads; idx++ )
+            {
+                browseSem.acquireUninterruptibly();
+            }
+
+            
+            Integer key = new Integer( 1023 );
+            IntWrapper value = btree.find( key );
+            value = new IntWrapper( -1 );
+            btree.insert( key, value, true );
+            
+            key = new Integer(46);
+            value = btree.find( key );
+            value = new IntWrapper( -1 );
+            
+            btree.insert( key, value , true );
+            for ( idx = 1024; idx < 2048; idx++ )
+            {
+                btree.insert( new Integer( idx ), new IntWrapper( idx ), true );
+            }
+
+            key = new Integer(1);
+            value = btree.find( key );
+            value = new IntWrapper( -1 );
+            
+            btree.insert( key, value , true );
+            btree.insert( new Integer(1024), new IntWrapper( -1 ), true );
+            
+            for ( idx = 10; idx < 20; idx++ )
+            {
+                btree.remove( new Integer( idx ) );
+            }
+
+            updateSem.release();
+
+            for ( idx = 0; idx < numReadThreads; idx++ )
+            {
+                browseSem.acquireUninterruptibly();
+            }
+
+            for ( idx = 0; idx < 10; idx++ )
+            {
+                btree.remove( new Integer( idx ) );
+            }
+
+            for ( idx = 20; idx < 1024; idx++ )
+            {
+                btree.remove( new Integer( idx ) );
+            }
+        }
+
+
+        public void run()
+        {
+            try
+            {
+                if ( readOnly )
+                {
+                    this.readOnlyActions();
+                }
+                else
+                {
+                    this.readWriteActions();
+                }
+            }
+            catch( IOException e )
+            {
+                e.printStackTrace();
+                assertTrue( false );
+            }
+            catch( InterruptedException e )
+            {
+                e.printStackTrace();
+                assertTrue( false );
+            }
+            
+        }
+    } // end of class BasicTestThread
+    
+    
+    @Test
+    public void testLongBrowsing() throws IOException, InterruptedException
+    {
+        RecordManager recman;
+        BTree<Integer, IntWrapper> tree;
+        int numElements = 10000;
+      
+        int idx;
+        int numReadThreads = 4;
+        LongBrowsingTestThread readThreads[] = new LongBrowsingTestThread[numReadThreads];
+        LongBrowsingTestThread updateThread;
+        
+        recman = RecordManagerFactory.createRecordManager( getTemporaryFile( "testLongBrowsing" ) );
+        SnapshotRecordManager snapshotRecman = new SnapshotRecordManager( recman, 1 << 10 );
+        
+        tree = new BTree<Integer, IntWrapper>( snapshotRecman, new IntegerComparator() );
+     
+        for ( idx = 0; idx < numElements; idx++ )
+        {
+            tree.insert( new Integer( idx ), new IntWrapper( 0 ), true );
+        }
+
+        for ( idx = 0; idx < numReadThreads; idx++ )
+        {
+            readThreads[idx] = new LongBrowsingTestThread( true, tree, numElements);
+        }
+        updateThread = new LongBrowsingTestThread( false, tree, numElements );      
+        
+        
+        readThreads[0].start();
+        
+        Thread.sleep( 10 );
+        
+        updateThread.start();
+        
+        for ( idx = 1; idx < numReadThreads; idx++ )
+        {
+            Thread.sleep( 1000 );
+            readThreads[idx].start();
+        }
+        
+        for ( idx = 0; idx < numReadThreads; idx++ )
+        {
+            readThreads[idx].join();
+        }
+        
+        updateThread.join();
+        
+        snapshotRecman.close();
+    }
+    
+    class LongBrowsingTestThread extends Thread
+    {
+        boolean readOnly;
+        BTree<Integer, IntWrapper> btree;
+        int numElements;
+       
+        
+        LongBrowsingTestThread( boolean readOnly, BTree<Integer, IntWrapper> btree, int numElements)
+        {
+            this.readOnly = readOnly;
+            this.btree = btree;
+            this.numElements = numElements;
+        }
+
+
+
+        private void readOnlyActions() throws IOException, InterruptedException
+        {
+            int count = 0;
+            TupleBrowser<Integer, IntWrapper> browser = btree.browse();
+            Tuple<Integer, IntWrapper> tuple = new Tuple();
+           
+            assertTrue( browser.getNext( tuple ) );
+            int max = tuple.getValue().value;
+            count++;
+            System.out.println( " TestLongBrowsing read thread min key is"  + tuple.getKey() + "max value is" + max );
+            
+            while( browser.getNext( tuple ) )
+            {
+                count++;
+
+                // Sleep for a while to keep browsing long                                                                                                                                                               
+                Thread.sleep( 10 );
+
+                
+                if ( tuple.getValue().value > max )
+                {
+                    System.out.println(" tupe value:" + tuple.getValue().value + " Expected max:" + max + " count:" + count);
+                    
+                }
+                
+                assertTrue( tuple.getValue().value <= max );
+                
+            }
+
+
+            System.out.println( "TestLongBrowsing read thread count is " + count );
+            assertEquals( count, numElements );
+            browser.close();
+        }
+        
+        private void readWriteActions()
+        {
+            int idx;
+            Random updateRandomizer = new Random();
+            
+            try
+            {
+                for ( idx = 1; idx < 100; idx++ )
+                {
+                    Integer key = new Integer( 0 );
+                    IntWrapper value = btree.find( key );
+                    value = new IntWrapper( idx );
+                    btree.insert( key, value, true );
+                    
+                    for ( int updates = 0; updates < 2048; updates++ )
+                    {
+                        key = new Integer( updateRandomizer.nextInt( numElements ) );
+                        value = btree.find( key );
+                        
+                        assertTrue( value.value <= idx );
+                        
+                        value = new IntWrapper( idx );
+                        btree.insert( key, value, true );
+                    }
+                }
+                
+                System.out.println( "TestLongBrowsing updates ended" );
+            
+            }
+            catch( IOException e )
+            {
+                e.printStackTrace();
+                assertTrue( false );
+            }
+        }
+
+
+        public void run()
+        {
+            try
+            {
+                if ( readOnly )
+                {
+                    this.readOnlyActions();
+                }
+                else
+                {
+                    this.readWriteActions();
+                }
+            }
+            catch( IOException e )
+            {
+                e.printStackTrace();
+                assertTrue( false );
+            }
+            catch( InterruptedException e )
+            {
+                e.printStackTrace();
+                assertTrue( false );
+            }
+            
+        }
+    } // end of class LongBrowsingTestThread
+    
+    
+    
+    @Test
+    public void testRemoveInsert() throws IOException, InterruptedException
+    {
+        RecordManager recman;
+        BTree<Integer, IntWrapper> tree;
+        int numElements = 10000;
+      
+        int idx;
+        int numReadThreads = 4;
+        RemoveInsertTestThread readThreads[] = new RemoveInsertTestThread[numReadThreads];
+        RemoveInsertTestThread updateThread;
+        
+        Semaphore browseSem = new Semaphore( 0 );
+        
+        recman = RecordManagerFactory.createRecordManager( getTemporaryFile( "testRemoveInsert" ) );
+        SnapshotRecordManager snapshotRecman = new SnapshotRecordManager( recman, 1 << 12 );
+        
+        tree = new BTree<Integer, IntWrapper>( snapshotRecman, new IntegerComparator() );
+     
+        for ( idx = 0; idx < numElements; idx++ )
+        {
+            tree.insert( new Integer( idx ), new IntWrapper( 0 ), true );
+        }
+
+        for ( idx = 0; idx < numReadThreads; idx++ )
+        {
+            readThreads[idx] = new RemoveInsertTestThread( true, tree, numElements, browseSem, numReadThreads );
+        }
+        updateThread = new RemoveInsertTestThread( false, tree, numElements, browseSem, numReadThreads );      
+        
+        
+        updateThread.start();
+        
+        for ( idx = 0; idx < numReadThreads; idx++ )
+        {
+            Thread.sleep( 1000 );
+            readThreads[idx].start();
+        }
+        
+        for ( idx = 0; idx < numReadThreads; idx++ )
+        {
+            readThreads[idx].join();
+        }
+        updateThread.join();
+        
+        snapshotRecman.close();
+    }
+    
+    
+    
+    class RemoveInsertTestThread extends Thread
+    {
+        boolean readOnly;
+        BTree<Integer, IntWrapper> btree;
+        int numElements;
+        Semaphore browseSem;
+        int numReadThreads;
+        
+        RemoveInsertTestThread( boolean readOnly, BTree<Integer, IntWrapper> btree, int numElements,  Semaphore browseSem, int numReadThreads )
+        {
+            this.readOnly = readOnly;
+            this.btree = btree;
+            this.numElements = numElements;
+            this.browseSem = browseSem;
+            this.numReadThreads = numReadThreads;
+        }
+
+        private void readOnlyActions() throws IOException, InterruptedException
+        {
+            int count = 0;
+            TupleBrowser<Integer, IntWrapper> browser = btree.browse();
+            Tuple<Integer, IntWrapper> tuple = new Tuple();
+           
+            browseSem.release();
+            
+            while( browser.getNext( tuple ) )
+            {
+                count++;
+
+                // Sleep for a while to keep browsing long                                                                                                                                                               
+                Thread.sleep( 10 );
+
+                
+                if ( tuple.getValue().value == -1 )
+                {
+                    System.out.println(" tupe key:" + tuple.getKey() + " value:" + tuple.getValue().value);
+                    
+                }
+                
+                assertTrue( tuple.getValue().value != -1 );
+            }
+
+
+            System.out.println( "TestRemoveInsert read thread count is " + count );
+            assertEquals( count, numElements );
+            browser.close();
+        }
+        
+        private void readWriteActions() throws IOException, InterruptedException
+        {
+            int idx;
+            Random updateRandomizer = new Random();
+            
+            for ( idx = 0; idx < numReadThreads; idx++ )
+            {
+                browseSem.acquireUninterruptibly();
+            }
+            
+          
+            Integer key;
+            IntWrapper value = new IntWrapper( -1 );
+            
+            for ( idx = 0; idx < 10; idx++ )
+            {
+                Thread.sleep( 10000 );
+                
+                int startingIndex = updateRandomizer.nextInt( numElements );
+                
+                for ( int updates = 0; updates < 32; updates++ )
+                {                    
+                    key = new Integer( startingIndex + updates );
+                    
+                    if ( key.intValue() >= numElements )
+                    {
+                        break;
+                    }   
+                        
+                    btree.remove( key );
+                }
+                
+                for ( int updates = 0; updates < 32; updates++ )
+                {
+                    key = new Integer( startingIndex + updates );
+                    btree.insert( key, value, true );
+                }
+            }
+            
+            System.out.println( "TestRemoveInsert updates ended" );
+            
+        }
+
+
+        public void run()
+        {         
+            try
+            {
+                if ( readOnly )
+                {
+                    this.readOnlyActions();
+                }
+                else
+                {
+                    this.readWriteActions();
+                }
+            }
+            catch( IOException e )
+            {
+                e.printStackTrace();
+                assertTrue( false );
+            }
+            catch( InterruptedException e )
+            {
+                e.printStackTrace();
+                assertTrue( false );
+            }
+            
+            
+        }
+    } // end of class RemoveInsertTestThread
+}
\ No newline at end of file

Added: directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestStreamCorrupted.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestStreamCorrupted.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestStreamCorrupted.java (added)
+++ directory/apacheds/trunk/jdbm2/src/test/java/jdbm/btree/TestStreamCorrupted.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,141 @@
+/**
+ * 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.
+ *
+ */
+package jdbm.btree;
+
+
+import java.io.IOException;
+
+import jdbm.RecordManager;
+import jdbm.RecordManagerFactory;
+import jdbm.helper.StringComparator;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Contributed test case for BTree by Christof Dallermassl (cdaller@iicm.edu):
+ *
+ * -= quote from original message posted on jdbm-general =-
+ * <pre>
+ *
+ * I tried to insert a couple of elements into a BTree and then remove
+ * them one by one. After a number or removals, there is always (if more
+ * than 20 elements in btree) a java.io.StreamCorruptedException thrown.
+ *
+ * The strange thing is, that on 50 elements, the exception is thrown
+ * after removing 22, on 200 it is thrown after 36, on 1000 it is thrown
+ * after 104, on 10000 it is thrown after 1003....
+ *
+ * The full stackTrace is here:
+ * ---------------------- snip ------- snap -------------------------
+ * java.io.StreamCorruptedException: Caught EOFException while reading the
+ * stream header
+ *   at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:845)
+ *   at java.io.ObjectInputStream.<init>(ObjectInputStream.java:168)
+ *   at jdbm.recman.RecordManager.byteArrayToObject(RecordManager.java:296)
+ *   at jdbm.recman.RecordManager.fetchObject(RecordManager.java:239)
+ *   at jdbm.helper.ObjectCache.fetchObject(ObjectCache.java:104)
+ *   at jdbm.btree.BPage.loadBPage(BPage.java:670)
+ *   at jdbm.btree.BPage.remove(BPage.java:492)
+ *   at jdbm.btree.BPage.remove(BPage.java:437)
+ *   at jdbm.btree.BTree.remove(BTree.java:313)
+ *   at JDBMTest.main(JDBMTest.java:41)
+ *
+ * </pre>
+ *
+ *  @author <a href="mailto:cdaller@iicm.edu">Christof Dallermassl</a>
+ */
+public class TestStreamCorrupted
+{
+    @Rule
+    public TemporaryFolder folder = new TemporaryFolder();
+
+
+    private String getTemporaryFile( String name ) throws IOException
+    {
+        String file = folder.newFile( name ).getAbsolutePath();
+        return file;
+    }
+
+
+    /**
+     *  Basic tests
+     */
+    @Test
+    public void testStreamCorrupted() throws IOException
+    {
+        RecordManager recman;
+        BTree<String, Integer> btree;
+        int iterations;
+
+        iterations = 100; // 23 works :-(((((
+
+        // open database
+        recman = RecordManagerFactory.createRecordManager( getTemporaryFile( "test" ) );
+
+        // create a new B+Tree data structure
+        btree = new BTree<String, Integer>( recman, new StringComparator() );
+        recman.setNamedObject( "testbtree", btree.getRecordId() );
+
+        // action:
+        // insert data
+        for( int count = 0; count < iterations; count++ ) 
+        {
+            btree.insert( "num" + count, Integer.valueOf( count ), true );
+        }
+
+        // delete data
+        for( int count = 0; count < iterations; count++ ) 
+        {
+            btree.remove( "num" + count );
+        }
+
+        // close database
+        recman.close();
+        recman = null;
+    }
+}

Added: directory/apacheds/trunk/jdbm2/src/test/java/jdbm/helper/TestActionVersioning.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/test/java/jdbm/helper/TestActionVersioning.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/test/java/jdbm/helper/TestActionVersioning.java (added)
+++ directory/apacheds/trunk/jdbm2/src/test/java/jdbm/helper/TestActionVersioning.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package jdbm.helper;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+/**
+ * 
+ * TODO TestActionVersioning.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TestActionVersioning
+{
+    @Test
+    public void testVersioning()
+    {
+        ActionVersioning.Version version1, version2;
+        ActionVersioning.Version writeVersion;
+        ActionVersioning.Version minVersion;
+        
+        ActionVersioning versioning = new ActionVersioning();
+        version1 = versioning.beginReadAction();
+        assertEquals( version1.getVersion(),  0 );
+        
+        writeVersion = versioning.beginWriteAction();      
+        assertEquals( writeVersion.getVersion(), 1 );
+        
+        version2 = versioning.beginReadAction();
+        assertEquals( version2.getVersion(), 0 );
+        
+        minVersion = versioning.endWriteAction();
+        assertEquals( minVersion.getVersion(), 0 );
+        
+        writeVersion = versioning.beginWriteAction();
+        assertEquals( writeVersion.getVersion(), 2 );
+        
+        minVersion = versioning.endWriteAction();
+        assertEquals( minVersion.getVersion(), 0 );
+        
+        versioning.endReadAction( version1 );
+        minVersion = versioning.endReadAction( version2 );
+        assertEquals( minVersion.getVersion(), 2 );
+        
+        version1  = versioning.beginReadAction();
+        assertEquals( version1.getVersion(), 2 );
+        
+        minVersion = versioning.endReadAction( version1 );
+        assertEquals( minVersion, null );
+        
+    }
+}
\ No newline at end of file

Added: directory/apacheds/trunk/jdbm2/src/test/java/jdbm/helper/TestVersionedCache.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/test/java/jdbm/helper/TestVersionedCache.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/test/java/jdbm/helper/TestVersionedCache.java (added)
+++ directory/apacheds/trunk/jdbm2/src/test/java/jdbm/helper/TestVersionedCache.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,271 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package jdbm.helper;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+/**
+ * 
+ * TODO TestVersionedCache.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TestVersionedCache
+{
+    private int expectedSum;
+    static final int THREAD_NUMBER = 5;
+    
+    
+    @Test
+    public void testBasics() throws IOException, CacheEvictionException
+    {
+        int idx;
+        int numEntries = 1024;
+        Integer intsArray[] = new Integer[numEntries];
+        
+        for ( idx = 0; idx < numEntries; idx++  )
+        {
+            intsArray[idx] = new Integer( 1 );
+        }
+        
+        ArrayEntryIO arrayIO = new ArrayEntryIO(intsArray);
+        
+        LRUCache<Integer, Integer> cache = new LRUCache<Integer, Integer>( arrayIO, numEntries );
+        
+        Integer val = cache.get( new Integer ( 5 ), 0, null, false );
+        assertEquals( val.intValue(), 1 );
+        
+        val = cache.get( new Integer ( 20 ), 0, null, false );
+        assertEquals( val.intValue(), 1 );
+        
+        cache.put( new Integer(1), 2, 1, null, false );
+        cache.put( new Integer(5), 2, 1, null, false );
+        cache.put( new Integer(30), 2, 1, null, false );
+        
+        int sum = 0;
+        for ( idx = 0; idx < numEntries; idx++ )
+        {
+            sum += cache.get( new Integer( idx ), 0, null, false ).intValue();
+        }
+        
+        assertEquals( sum, numEntries );
+
+        sum = 0;
+        cache.advanceMinReadVersion( 1 );
+        for ( idx = 0; idx < numEntries; idx++ )
+        {
+            sum += cache.get( new Integer( idx ), 1, null, false ).intValue();
+        }
+        
+        System.out.println( "Sum is: "+ sum);
+        assertEquals( sum, ( numEntries + 3 ) );
+        
+    }
+    
+    @Test
+    public void testMultiThreadedAccess() throws IOException, CacheEvictionException
+    {
+        int idx;
+        int numEntries = 1024;
+        Integer intsArray[] = new Integer[numEntries];
+        
+        for ( idx = 0; idx < numEntries; idx++  )
+        {
+            intsArray[idx] = new Integer( 1 );
+        }
+        
+        ArrayEntryIO arrayIO = new ArrayEntryIO(intsArray, 10, 20);
+        
+        LRUCache<Integer, Integer> cache = new LRUCache<Integer, Integer>( arrayIO, numEntries );
+        
+        TestThread[] threadPool =  new TestThread[THREAD_NUMBER];
+    
+        // create content for the tree, different content for different threads!
+        for ( int threadCount = 0; threadCount < THREAD_NUMBER; threadCount++ )
+        {
+            if ( threadCount == ( THREAD_NUMBER - 1 ) )
+                threadPool[threadCount] = new TestThread( false, intsArray, cache );
+            else
+                threadPool[threadCount] = new TestThread( true, intsArray, cache );
+                
+            threadPool[threadCount].start();
+        }
+
+        // wait until the threads really stop:
+        try
+        {
+            for ( int threadCount = 0; threadCount < THREAD_NUMBER; threadCount++ )
+            {
+                threadPool[threadCount].join();
+            }
+        }
+        catch ( InterruptedException ignore )
+        {
+            ignore.printStackTrace();
+        }
+        
+        int sum = 0;
+        cache.advanceMinReadVersion( 2 );        
+        for ( idx = 0; idx < intsArray.length; idx++ )
+        {
+            sum += cache.get( new Integer( idx ), 2, null, false ).intValue();
+        }
+        
+        assertEquals( sum, expectedSum );
+        
+
+    }
+    
+    
+    private class ArrayEntryIO implements EntryIO<Integer, Integer>
+    {
+        Integer intsArray[];
+        int readSleepTime;
+        int writeSleepTime;
+        
+        public ArrayEntryIO( Integer intsArray[] )
+        {
+            this.intsArray = intsArray;
+        }
+        
+        public ArrayEntryIO( Integer intsArray[], int readSleepTIme, int writeSleepTime )
+        {
+            this.intsArray = intsArray;
+            this.readSleepTime = readSleepTime;
+            this.writeSleepTime = writeSleepTime;
+        }
+        
+        public Integer read( Integer key, Serializer serializer) throws IOException
+        {
+            if ( readSleepTime != 0 )
+            {
+                try
+                {
+                    Thread.sleep( readSleepTime );
+                }
+                catch ( InterruptedException e )
+                {
+                    // ignore
+                }
+            }
+            
+            return intsArray[key.intValue()];
+        }
+        
+        public void write( Integer key, Integer value, Serializer serializer ) throws IOException
+        {
+            if ( writeSleepTime != 0 )
+            {
+                try
+                {
+                    Thread.sleep( writeSleepTime );
+                }
+                catch ( InterruptedException e )
+                {
+                    // ignore
+                }
+            }
+            
+            intsArray[key.intValue()] = value;
+        }
+    }
+    
+    
+    class TestThread extends Thread
+    {
+        boolean readOnly;
+        Integer intsArray[];
+        LRUCache<Integer, Integer> cache;
+
+        TestThread( boolean readOnly, Integer intsArray[] , LRUCache<Integer, Integer> cache)
+        {
+            this.readOnly = readOnly;
+            this.intsArray = intsArray;
+            this.cache = cache;
+        }
+
+
+
+        private void action() throws IOException, CacheEvictionException
+        {
+            int idx;
+            int sum = 0;
+            if ( readOnly )
+            {
+               
+                for ( idx = 0; idx < intsArray.length; idx++ )
+                {
+                    sum += cache.get( new Integer( idx ), 0, null, false ).intValue();
+                }
+                
+                assertEquals( sum, intsArray.length );
+            }
+            else
+            {
+                expectedSum = intsArray.length;
+                
+                for ( idx = 0; idx <= intsArray.length; idx = idx + 100)
+                {
+                    cache.put( new Integer( idx ), 2, 1, null, false );
+                    expectedSum = expectedSum + 1;
+                }
+                
+                for ( idx = 0; idx <= intsArray.length; idx = idx + 100)
+                {
+                    cache.put( new Integer( idx ), 3, 2, null, false );
+                    expectedSum = expectedSum + 1;
+                }
+                
+                for ( idx = 0; idx < intsArray.length; idx++ )
+                {
+                    sum += cache.get( new Integer( idx ), 2, null, false ).intValue();
+                }
+                
+                assertEquals( sum, expectedSum );
+            }
+        }
+
+
+        public void run()
+        {
+            try
+            {
+                this.action();
+            }
+            catch ( IOException e)
+            {
+            }
+            catch ( CacheEvictionException e)
+            {
+            }
+        }
+    } // end of class TestThread
+}
\ No newline at end of file

Added: directory/apacheds/trunk/jdbm2/src/test/java/jdbm/recman/BlockIoTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/test/java/jdbm/recman/BlockIoTest.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/test/java/jdbm/recman/BlockIoTest.java (added)
+++ directory/apacheds/trunk/jdbm2/src/test/java/jdbm/recman/BlockIoTest.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,217 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package jdbm.recman;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class BlockIoTest
+{
+    BlockIo blockIo;
+    BlockIo blockIoData;
+    
+    @Before
+    public void init()
+    {
+        blockIo = new BlockIo( 0L, new byte[1024] );
+        
+        // Init the blockIo with 1024 bytes from 0x00 to 0xFF, 4 times
+        for ( int i = 0; i < 1024; i++ )
+        {
+            blockIo.writeByte( i, (byte)( i & 0x00fff ) );
+        }
+        
+        blockIoData = new BlockIo( 0L, new byte[1024] );
+        blockIoData.writeLong( 0, 0x8081828384858687L );
+        blockIoData.writeInt( 8, 0x000000ff );
+        
+        for ( int i = 0; i < 256; i++ )
+        {
+            blockIoData.writeByte( 12+i, (byte)0x80 );
+        }
+    }
+
+    
+    @Test
+    public void testReadByte()
+    {
+        assertEquals( (byte)0x00, blockIo.readByte( 0 ) );
+        assertEquals( (byte)0xff, blockIo.readByte( 1023 ) );
+        
+        try
+        {
+            blockIo.readByte( -1 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+        
+        try
+        {
+            blockIo.readByte( 1024 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+    }
+
+    
+    @Test
+    public void testReadInt()
+    {
+        assertEquals( 0x00010203, blockIo.readInt( 0 ) );
+        assertEquals( 0x7c7d7e7f, blockIo.readInt( 124 ) );
+        assertEquals( 0x7d7e7f80, blockIo.readInt( 125 ) );
+        assertEquals( 0x7e7f8081, blockIo.readInt( 126 ) );
+        assertEquals( 0x7f808182, blockIo.readInt( 127 ) );
+        assertEquals( 0x80818283, blockIo.readInt( 128 ) );
+        assertEquals( 0xfbfcfdfe, blockIo.readInt( 1019 ) );
+        assertEquals( 0xfcfdfeff, blockIo.readInt( 1020 ) );
+        
+        try
+        {
+            blockIo.readInt( -1 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+        
+        try
+        {
+            blockIo.readInt( 1021 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+        
+        try
+        {
+            blockIo.readInt( 1024 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+    }
+
+    
+    @Test
+    public void testReadShort()
+    {
+        assertEquals( 0x0001, blockIo.readShort( 0 ) );
+        assertEquals( 0x7c7d, blockIo.readShort( 124 ) );
+        assertEquals( 0x7d7e, blockIo.readShort( 125 ) );
+        assertEquals( 0x7e7f, blockIo.readShort( 126 ) );
+        assertEquals( 0x7f80, blockIo.readShort( 127 ) );
+        assertEquals( (short)0x8081, blockIo.readShort( 128 ) );
+        assertEquals( (short)0xfdfe, blockIo.readShort( 1021 ) );
+        assertEquals( (short)0xfeff, blockIo.readShort( 1022 ) );
+        
+        try
+        {
+            blockIo.readShort( -1 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+        
+        try
+        {
+            blockIo.readShort( 1023 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+        
+        try
+        {
+            blockIo.readShort( 1024 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+    }
+
+    
+    @Test
+    public void testReadLong()
+    {
+        assertEquals( 0x0001020304050607L, blockIo.readLong( 0 ) );
+        assertEquals( 0x78797a7b7c7d7e7fL, blockIo.readLong( 120 ) );
+        assertEquals( 0x797a7b7c7d7e7f80L, blockIo.readLong( 121 ) );
+        assertEquals( 0x7a7b7c7d7e7f8081L, blockIo.readLong( 122 ) );
+        assertEquals( 0x7b7c7d7e7f808182L, blockIo.readLong( 123 ) );
+        assertEquals( 0x7c7d7e7f80818283L, blockIo.readLong( 124 ) );
+        assertEquals( 0x7d7e7F8081828384L, blockIo.readLong( 125 ) );
+        assertEquals( 0x7e7f808182838485L, blockIo.readLong( 126 ) );
+        assertEquals( 0x7f80818283848586L, blockIo.readLong( 127 ) );
+        assertEquals( 0x8081828384858687L, blockIo.readLong( 128 ) );
+        assertEquals( 0xf7f8f9fafbfcfdfeL, blockIo.readLong( 1015 ) );
+        assertEquals( 0xf8f9fafbfcfdfeffL, blockIo.readLong( 1016 ) );
+        
+        try
+        {
+            blockIo.readLong( -1 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+        
+        try
+        {
+            blockIo.readLong( 1017 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+        
+        try
+        {
+            blockIo.readLong( 1024 );
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            // Expected
+        }
+    }
+}

Added: directory/apacheds/trunk/jdbm2/src/test/java/jdbm/recman/LocationTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/test/java/jdbm/recman/LocationTest.java?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/test/java/jdbm/recman/LocationTest.java (added)
+++ directory/apacheds/trunk/jdbm2/src/test/java/jdbm/recman/LocationTest.java Thu Feb  2 12:38:39 2012
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package jdbm.recman;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class LocationEntry.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LocationTest
+{
+    private static Location clonedServerEntryA;
+    private static Location clonedServerEntryACopy;
+    private static Location clonedServerEntryB;
+    private static Location clonedServerEntryA1;
+    private static Location clonedServerEntryACopy1;
+    private static Location clonedServerEntryB1;
+    private static Location clonedServerEntryC1;
+    private static Location clonedServerEntryD1;
+
+
+    /**
+     * Initialize name instances
+     */
+    @BeforeClass
+    public static void initNames() throws Exception
+    {
+        clonedServerEntryA = new Location( 1L );
+        clonedServerEntryACopy = new Location( 1L );
+        clonedServerEntryB = new Location( 1L );
+        clonedServerEntryA1 = new Location( 1L, ( short ) 1 );
+        clonedServerEntryACopy1 = new Location( 1L, ( short ) 1 );
+        clonedServerEntryB1 = new Location( 1L, ( short ) 1 );
+        clonedServerEntryC1 = new Location( 1L, ( short ) 2 );
+        clonedServerEntryD1 = new Location( 2L, ( short ) 1 );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( clonedServerEntryA.equals( null ) );
+        assertFalse( clonedServerEntryA1.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( clonedServerEntryA, clonedServerEntryA );
+        assertEquals( clonedServerEntryA1, clonedServerEntryA1 );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( clonedServerEntryA.hashCode(), clonedServerEntryA.hashCode() );
+        assertEquals( clonedServerEntryA1.hashCode(), clonedServerEntryA1.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( clonedServerEntryA, clonedServerEntryACopy );
+        assertEquals( clonedServerEntryACopy, clonedServerEntryA );
+        assertEquals( clonedServerEntryA1, clonedServerEntryACopy1 );
+        assertEquals( clonedServerEntryACopy1, clonedServerEntryA1 );
+    }
+
+
+    @Test
+    @Ignore
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( clonedServerEntryA.hashCode(), clonedServerEntryACopy.hashCode() );
+        assertEquals( clonedServerEntryACopy.hashCode(), clonedServerEntryA.hashCode() );
+        assertEquals( clonedServerEntryA1.hashCode(), clonedServerEntryACopy1.hashCode() );
+        assertEquals( clonedServerEntryACopy1.hashCode(), clonedServerEntryA1.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( clonedServerEntryA, clonedServerEntryACopy );
+        assertEquals( clonedServerEntryACopy, clonedServerEntryB );
+        assertEquals( clonedServerEntryA, clonedServerEntryB );
+        assertEquals( clonedServerEntryA1, clonedServerEntryACopy1 );
+        assertEquals( clonedServerEntryACopy1, clonedServerEntryB1 );
+        assertEquals( clonedServerEntryA1, clonedServerEntryB1 );
+    }
+
+
+    @Test
+    @Ignore
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( clonedServerEntryA.hashCode(), clonedServerEntryACopy.hashCode() );
+        assertEquals( clonedServerEntryACopy.hashCode(), clonedServerEntryB.hashCode() );
+        assertEquals( clonedServerEntryA.hashCode(), clonedServerEntryB.hashCode() );
+        assertEquals( clonedServerEntryA1.hashCode(), clonedServerEntryACopy1.hashCode() );
+        assertEquals( clonedServerEntryACopy1.hashCode(), clonedServerEntryB1.hashCode() );
+        assertEquals( clonedServerEntryA1.hashCode(), clonedServerEntryB1.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( clonedServerEntryA1.equals( clonedServerEntryC1 ) );
+        assertFalse( clonedServerEntryC1.equals( clonedServerEntryA1 ) );
+        assertFalse( clonedServerEntryA1.equals( clonedServerEntryD1 ) );
+        assertFalse( clonedServerEntryD1.equals( clonedServerEntryA1 ) );
+    }
+}

Added: directory/apacheds/trunk/jdbm2/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm2/src/test/resources/log4j.properties?rev=1239581&view=auto
==============================================================================
--- directory/apacheds/trunk/jdbm2/src/test/resources/log4j.properties (added)
+++ directory/apacheds/trunk/jdbm2/src/test/resources/log4j.properties Thu Feb  2 12:38:39 2012
@@ -0,0 +1,22 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=ERROR, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
+