directory-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Selcuk AYA <ayasel...@gmail.com>
Subject Re: svn commit: r1161416 - in /directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm: btree/BPage.java btree/BTree.java helper/TupleBrowser.java recman/BaseRecordManager.java
Date Thu, 25 Aug 2011 13:15:34 GMT
On Thu, Aug 25, 2011 at 3:55 PM, Pierre-Arnaud Marcelot <pa@marcelot.net> wrote:
> I'm getting the following test failures in jdbm-partition:
>
> [INFO]
> ------------------------------------------------------------------------
> [INFO] Building ApacheDS JDBM Partition 2.0.0-M3-SNAPSHOT
> [INFO]
> ------------------------------------------------------------------------
> [INFO]
> [INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @
> apacheds-jdbm-partition ---
> [INFO] Deleting
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm-partition/target
> [INFO]
> [INFO] --- maven-remote-resources-plugin:1.2:process (default) @
> apacheds-jdbm-partition ---
> [INFO]
> [INFO] --- maven-resources-plugin:2.5:resources (default-resources) @
> apacheds-jdbm-partition ---
> [debug] execute contextualize
> [INFO] Using 'UTF-8' encoding to copy filtered resources.
> [INFO] skip non existing resourceDirectory
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm-partition/src/main/resources
> [INFO] Copying 3 resources
> [INFO]
> [INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @
> apacheds-jdbm-partition ---
> [INFO] Compiling 20 source files to
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm-partition/target/classes
> [INFO]
> [INFO] --- maven-resources-plugin:2.5:testResources (default-testResources)
> @ apacheds-jdbm-partition ---
> [debug] execute contextualize
> [INFO] Using 'UTF-8' encoding to copy filtered resources.
> [INFO] Copying 1 resource
> [INFO] Copying 3 resources
> [INFO]
> [INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @
> apacheds-jdbm-partition ---
> [INFO] Compiling 20 source files to
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm-partition/target/test-classes
> [INFO]
> [INFO] --- maven-surefire-plugin:2.8:test (default-test) @
> apacheds-jdbm-partition ---
> [INFO] Surefire report directory:
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm-partition/target/surefire-reports
> -------------------------------------------------------
>  T E S T S
> -------------------------------------------------------
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.BTreeRedirectMarshallerTest
> Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.211 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.DupsContainerCursorTest
> Tests run: 5, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 2.526 sec
> <<< FAILURE!
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest
> Tests run: 15, Failures: 0, Errors: 12, Skipped: 0, Time elapsed: 1.4 sec
> <<< FAILURE!
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmBrowserBugTest
> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.024 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndexTest
> Tests run: 15, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.865 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmMasterTableTest
> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.553 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmRdnIndexTest
> Tests run: 8, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.583 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmStoreTest
> Tests run: 18, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.443 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableNoDuplicatesTest
> Tests run: 8, Failures: 0, Errors: 6, Skipped: 0, Time elapsed: 1.135 sec
> <<< FAILURE!
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest
> Tests run: 15, Failures: 0, Errors: 9, Skipped: 0, Time elapsed: 0.918 sec
> <<< FAILURE!
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.KeyBTreeCursorTest
> Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.071 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.KeyCursorTest
> Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.06 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.KeyTupleArrayCursorTest
> Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.KeyTupleBTreeCursorTest
> Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.558 sec
> <<< FAILURE!
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.NoDupsCursorTest
> Tests run: 5, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.491 sec
> <<< FAILURE!
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.ServerEntrySerializerTest
> Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.466 sec
> Running
> org.apache.directory.server.core.partition.impl.btree.jdbm.StringSerializerTest
> Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.058 sec
> Running org.apache.directory.server.core.partition.tree.PartitionTreeTest
> Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.454 sec
> Running org.apache.directory.server.core.schema.PartitionSchemaLoaderTest
> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.377 sec
> Results :
> Tests in error:
>
> testOnTableWithMultipleEntries(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsContainerCursorTest)
>
> testNextNoDups(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testPreviousNoDups(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testNextDups(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testPreviousDups(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testFirstLastUnderDupLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testFirstLastOverDupLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testFirstOverDupLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testLastOverDupLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testOverDupLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testUnderDupLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testBeforeAfterBelowDupLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testBeforeAfterOverDupLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.DupsCursorTest)
>
> testCloseReopen(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableNoDuplicatesTest)
>
> testLoadData(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableNoDuplicatesTest)
>
> testNullOrEmptyKeyValue(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableNoDuplicatesTest)
>
> testRemove(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableNoDuplicatesTest)
>
> testPut(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableNoDuplicatesTest)
>
> testHas(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableNoDuplicatesTest)
>
> testMiscellaneous(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testCloseReopen(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testLoadData(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testNullOrEmptyKeyValue(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testRemove(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testPut(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testHas(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testDuplicateLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testNullOrEmptyKeyValueAfterDuplicateLimit(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
>
> testNonEmptyCursor(org.apache.directory.server.core.partition.impl.btree.jdbm.KeyTupleBTreeCursorTest)
>
> testOnTableWithMultipleEntries(org.apache.directory.server.core.partition.impl.btree.jdbm.NoDupsCursorTest)
> Tests run: 127, Failures: 0, Errors: 30, Skipped: 0
>
> Did I miss something?!?
> Is there another patch to apply, other than the 'jdbm1.diff' file?

jdbm1.diff is the only patch. I will take a look at the test failures.


> Regards,
> Pierre-Arnaud
regards,
Selcuk Aya

> On 25 août 2011, at 14:49, Pierre-Arnaud Marcelot wrote:
>
> OK,
> I moved the two test classes to their dedicated package 'jdbm.helper'.
> And fixed the compilation failure in Maven (strangely it was fine in
> Eclipse) by replacing this in:
>
> lrus = (LRUCache<K,V>.LRU [] )new LRUCache.LRU[NUM_LRUS];
>
> by this:
>
> lrus = ( LRUCache.LRU[] ) new LRUCache.LRU[NUM_LRUS];
>
> Compilation is now fine in Eclipse *and* Maven.
> Now, running all tests.
> Regards,
> Pierre-Arnaud
>
> On 25 août 2011, at 14:42, Pierre-Arnaud Marcelot wrote:
>
> I'm having trouble applying the 'jdbm1.diff' patch.
> Patching went fine, however there are two test classes that are not in the
> correct package, TestActionVersioning and TestVersionedCache, and Maven is
> reporting a compilation failure:
>
> [ERROR] Failed to execute goal
> org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile
> (default-compile) on project apacheds-jdbm: Compilation failure: Compilation
> failure:
> [ERROR]
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/LRUCache.java:[118,28]
> ')' expected
> [ERROR]
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/LRUCache.java:[118,29]
> ';' expected
> [ERROR]
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/LRUCache.java:[118,33]
> illegal start of expression
> [ERROR]
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/LRUCache.java:[118,34]
> ';' expected
> [ERROR]
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/LRUCache.java:[118,36]
> illegal start of expression
> [ERROR]
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/LRUCache.java:[118,37]
> ';' expected
> [ERROR]
> /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/LRUCache.java:[118,54]
> not a statement
>
> More to come...
> Regards,
> Pierre-Arnaud
> On 25 août 2011, at 13:58, Pierre-Arnaud Marcelot wrote:
>
> Sure, I'm on it.
> Regards,
> Pierre-Arnaud
> On 25 août 2011, at 13:41, Emmanuel Lecharny wrote:
>
> Strange... I did a pacth -p0 with your diff.
>
> I may have not svn added the files.
>
> i'm not connected right now (using a client internet connection, will do
> that tonite
>
> Or maybe Pierre-Arnaud can apply the patch, do a svn add of the added files
> and commit ?
>
> On Thu, Aug 25, 2011 at 9:41 AM, Selcuk AYA <ayaselcuk@gmail.com> wrote:
>>
>> Hi,
>> there are alos a bunch of new filesn the patch I provided. Can you
>> also add them to the branch?
>>
>> A    jdbm/src/test/java/jdbm/helper
>> A    jdbm/src/test/java/jdbm/btree/SnapshotBTree.java
>> A    jdbm/src/test/java/jdbm/TestActionVersioning.java
>> A    jdbm/src/test/java/jdbm/TestVersionedCache.java
>> A    jdbm/src/main/java/jdbm/helper/ExplicitList.java
>> A    jdbm/src/main/java/jdbm/helper/ActionVersioning.java
>> A    jdbm/src/main/java/jdbm/helper/ActionContext.java
>> A    jdbm/src/main/java/jdbm/helper/LRUCache.java
>> A    jdbm/src/main/java/jdbm/helper/EntryIO.java
>> A    jdbm/src/main/java/jdbm/recman/SnapshotRecordManager.java
>> A    jdbm/src/main/java/jdbm/ActionRecordManager.java
>>
>> regards,
>> Selcuk
>>
>> On Thu, Aug 25, 2011 at 9:58 AM,  <elecharny@apache.org> wrote:
>> > Author: elecharny
>> > Date: Thu Aug 25 06:58:36 2011
>> > New Revision: 1161416
>> >
>> > URL: http://svn.apache.org/viewvc?rev=1161416&view=rev
>> > Log:
>> > applied Selcuk's patch
>> >
>> > Modified:
>> >
>> >  directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BPage.java
>> >
>> >  directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BTree.java
>> >
>> >  directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/TupleBrowser.java
>> >
>> >  directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java
>> >
>> > Modified:
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BPage.java
>> > URL:
>> > http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BPage.java?rev=1161416&r1=1161415&r2=1161416&view=diff
>> >
>> > ==============================================================================
>> > ---
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BPage.java
>> > (original)
>> > +++
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BPage.java
>> > Thu Aug 25 06:58:36 2011
>> > @@ -50,6 +50,7 @@ package jdbm.btree;
>> >  import jdbm.helper.Serializer;
>> >  import jdbm.helper.Tuple;
>> >  import jdbm.helper.TupleBrowser;
>> > +import jdbm.helper.ActionContext;
>> >
>> >  import java.io.IOException;
>> >  import java.io.ByteArrayOutputStream;
>> > @@ -259,10 +260,11 @@ public class BPage<K, V> implements Seri
>> >      *
>> >      * @param height Height of the current BPage (zero is leaf page)
>> >      * @param key The key
>> > +     * @param context action specific context. not null if record
>> > manager is action capable
>> >      * @return TupleBrowser positionned just before the given key, or
>> > before
>> >      *                      next greater key if key isn't found.
>> >      */
>> > -    TupleBrowser<K, V> find( int height, K key ) throws IOException
>> > +    TupleBrowser<K, V> find( int height, K key, ActionContext context )
>> > throws IOException
>> >     {
>> >         int index = this.findChildren( key );
>> >
>> > @@ -285,26 +287,27 @@ public class BPage<K, V> implements Seri
>> >             }
>> >         }
>> >
>> > -        return new Browser( child, index );
>> > +        return new Browser( child, index, context );
>> >     }
>> >
>> >
>> >     /**
>> >      * Find first entry and return a browser positioned before it.
>> >      *
>> > +     * @param context action specific context. not null if record
>> > manager is action capable
>> >      * @return TupleBrowser positionned just before the first entry.
>> >      */
>> > -    TupleBrowser<K, V> findFirst() throws IOException
>> > +    TupleBrowser<K, V> findFirst(ActionContext context ) throws
>> > IOException
>> >     {
>> >         if ( isLeaf )
>> >         {
>> > -            return new Browser( this, first );
>> > +            return new Browser( this, first, context );
>> >         }
>> >         else
>> >         {
>> >             BPage<K, V> child = childBPage( first );
>> >
>> > -            return child.findFirst();
>> > +            return child.findFirst( context );
>> >         }
>> >     }
>> >
>> > @@ -337,9 +340,12 @@ public class BPage<K, V> implements Seri
>> >
>> >         height -= 1;
>> >
>> > +        BPage<K,V> pageNewCopy = null;
>> >         if ( height == 0 )
>> >         {
>> > +            pageNewCopy = btree.copyOnWrite( this );
>> >             result = new InsertResult<K, V>();
>> > +            result.pageNewCopy = pageNewCopy;
>> >
>> >             // inserting on a leaf BPage
>> >             overflow = -1;
>> > @@ -365,8 +371,8 @@ public class BPage<K, V> implements Seri
>> >
>> >                 if ( replace )
>> >                 {
>> > -                    values[index] = value;
>> > -                    btree.recordManager.update( recordId, this, this );
>> > +                    pageNewCopy.values[index] = value;
>> > +                    btree.recordManager.update( recordId, pageNewCopy,
>> > this );
>> >                 }
>> >
>> >                 // return the existing key
>> > @@ -378,6 +384,11 @@ public class BPage<K, V> implements Seri
>> >             // non-leaf BPage
>> >             BPage<K, V> child = childBPage( index );
>> >             result = child.insert( height, key, value, replace );
>> > +            if( result.pageNewCopy != null)
>> > +            {
>> > +                child = result.pageNewCopy;
>> > +                result.pageNewCopy = null;
>> > +            }
>> >
>> >             if ( result.existing != null )
>> >             {
>> > @@ -393,6 +404,9 @@ public class BPage<K, V> implements Seri
>> >
>> >             // there was an overflow, we need to insert the overflow
>> > page
>> >             // on this BPage
>> > +            pageNewCopy = btree.copyOnWrite( this );
>> > +            result.pageNewCopy = pageNewCopy;
>> > +
>> >             if ( DEBUG )
>> >             {
>> >                 System.out.println( "BPage.insert() Overflow page: " +
>> > result.overflow.recordId );
>> > @@ -402,7 +416,7 @@ public class BPage<K, V> implements Seri
>> >             overflow = result.overflow.recordId;
>> >
>> >             // update child's largest key
>> > -            keys[index] = child.getLargestKey();
>> > +            pageNewCopy.keys[index] = child.getLargestKey();
>> >
>> >             // clean result so we can reuse it
>> >             result.overflow = null;
>> > @@ -410,24 +424,25 @@ public class BPage<K, V> implements Seri
>> >
>> >         // if we get here, we need to insert a new entry on the BPage
>> >         // before children[ index ]
>> > -        if ( !isFull() )
>> > -        {
>> > +        if ( !pageNewCopy.isFull() )
>> > +        {
>> >             if ( height == 0 )
>> >             {
>> > -                insertEntry( this, index - 1, key, value );
>> > +                insertEntry( pageNewCopy, index - 1, key, value );
>> >             }
>> >             else
>> >             {
>> > -                insertChild( this, index - 1, key, overflow );
>> > +                insertChild( pageNewCopy, index - 1, key, overflow );
>> >             }
>> >
>> > -            btree.recordManager.update( recordId, this, this );
>> > +            btree.recordManager.update( recordId, pageNewCopy, this );
>> >             return result;
>> >         }
>> >
>> >         // page is full, we must divide the page
>> >         int half = btree.pageSize >> 1;
>> > -        BPage<K, V> newPage = new BPage<K, V>( btree, isLeaf );
>> > +        BPage<K, V> newPage = new BPage<K, V>( btree,
>> > pageNewCopy.isLeaf );
>> > +
>> >
>> >         if ( index < half )
>> >         {
>> > @@ -441,15 +456,15 @@ public class BPage<K, V> implements Seri
>> >
>> >             if ( height == 0 )
>> >             {
>> > -                copyEntries( this, 0, newPage, half, index );
>> > +                copyEntries( pageNewCopy, 0, newPage, half, index );
>> >                 setEntry( newPage, half + index, key, value );
>> > -                copyEntries( this, index, newPage, half + index + 1,
>> > half - index - 1 );
>> > +                copyEntries( pageNewCopy, index, newPage, half + index
>> > + 1, half - index - 1 );
>> >             }
>> >             else
>> >             {
>> > -                copyChildren( this, 0, newPage, half, index );
>> > +                copyChildren( pageNewCopy, 0, newPage, half, index );
>> >                 setChild( newPage, half + index, key, overflow );
>> > -                copyChildren( this, index, newPage, half + index + 1,
>> > half - index - 1 );
>> > +                copyChildren( pageNewCopy, index, newPage, half + index
>> > + 1, half - index - 1 );
>> >             }
>> >         }
>> >         else
>> > @@ -463,50 +478,51 @@ public class BPage<K, V> implements Seri
>> >
>> >             if ( height == 0 )
>> >             {
>> > -                copyEntries( this, 0, newPage, half, half );
>> > -                copyEntries( this, half, this, half - 1, index - half
>> > );
>> > -                setEntry( this, index - 1, key, value );
>> > +                copyEntries( pageNewCopy, 0, newPage, half, half );
>> > +                copyEntries( pageNewCopy, half, pageNewCopy, half - 1,
>> > index - half );
>> > +                setEntry( pageNewCopy, index - 1, key, value );
>> >             }
>> >             else
>> >             {
>> > -                copyChildren( this, 0, newPage, half, half );
>> > -                copyChildren( this, half, this, half - 1, index - half
>> > );
>> > -                setChild( this, index - 1, key, overflow );
>> > +                copyChildren( pageNewCopy, 0, newPage, half, half );
>> > +                copyChildren( pageNewCopy, half, pageNewCopy, half - 1,
>> > index - half );
>> > +                setChild( pageNewCopy, index - 1, key, overflow );
>> >             }
>> >         }
>> >
>> > -        first = half - 1;
>> > +        pageNewCopy.first = half - 1;
>> >
>> >         // nullify lower half of entries
>> > -        for ( int i = 0; i < first; i++ )
>> > +        for ( int i = 0; i < pageNewCopy.first; i++ )
>> >         {
>> >             if ( height == 0 )
>> >             {
>> > -                setEntry( this, i, null, null );
>> > +                setEntry( pageNewCopy, i, null, null );
>> >             }
>> >             else
>> >             {
>> > -                setChild( this, i, null, -1 );
>> > +                setChild( pageNewCopy, i, null, -1 );
>> >             }
>> >         }
>> >
>> > -        if ( isLeaf )
>> > +        if ( pageNewCopy.isLeaf )
>> >         {
>> >             // link newly created BPage
>> > -            newPage.previous = previous;
>> > -            newPage.next = recordId;
>> > +            newPage.previous = pageNewCopy.previous;
>> > +            newPage.next = pageNewCopy.recordId;
>> >
>> > -            if ( previous != 0 )
>> > +            if ( pageNewCopy.previous != 0 )
>> >             {
>> > -                BPage<K, V> previousBPage = loadBPage( previous );
>> > +                BPage<K, V> previousBPage = loadBPage(
>> > pageNewCopy.previous );
>> > +                previousBPage = btree.copyOnWrite( previousBPage );
>> >                 previousBPage.next = newPage.recordId;
>> > -                btree.recordManager.update( previous, previousBPage,
>> > this );
>> > +                btree.recordManager.update( pageNewCopy.previous,
>> > previousBPage, this );
>> >             }
>> >
>> > -            previous = newPage.recordId;
>> > +            pageNewCopy.previous = newPage.recordId;
>> >         }
>> >
>> > -        btree.recordManager.update( recordId, this, this );
>> > +        btree.recordManager.update( recordId, pageNewCopy, this );
>> >         btree.recordManager.update( newPage.recordId, newPage, this );
>> >
>> >         result.overflow = newPage;
>> > @@ -521,9 +537,9 @@ public class BPage<K, V> implements Seri
>> >      * @param key Removal key
>> >      * @return Remove result object
>> >      */
>> > -    RemoveResult<V> remove( int height, K key ) throws IOException
>> > +    RemoveResult<K, V> remove( int height, K key ) throws IOException
>> >     {
>> > -        RemoveResult<V> result;
>> > +        RemoveResult<K, V> result;
>> >
>> >         int half = btree.pageSize / 2;
>> >         int index = findChildren( key );
>> > @@ -536,6 +552,7 @@ public class BPage<K, V> implements Seri
>> >
>> >         height -= 1;
>> >
>> > +        BPage<K,V> pageNewCopy = btree.copyOnWrite( this );;
>> >         if ( height == 0 )
>> >         {
>> >             // remove leaf entry
>> > @@ -544,22 +561,32 @@ public class BPage<K, V> implements Seri
>> >                 throw new IllegalArgumentException( I18n.err(
>> > I18n.ERR_514, key ) );
>> >             }
>> >
>> > -            result = new RemoveResult<V>();
>> > -            result.value = values[index];
>> > -            removeEntry( this, index );
>> > +            result = new RemoveResult<K, V>();
>> > +            result.value = pageNewCopy.values[index];
>> > +            removeEntry( pageNewCopy, index );
>> >
>> >             // update this BPage
>> > -            btree.recordManager.update( recordId, this, this );
>> > +            btree.recordManager.update( recordId, pageNewCopy, this );
>> >         }
>> >         else
>> >         {
>> >             // recurse into Btree to remove entry on a children page
>> >             BPage<K, V> child = childBPage( index );
>> >             result = child.remove( height, key );
>> > +
>> > +            if ( result.pageNewCopy != null )
>> > +            {
>> > +                child = result.pageNewCopy;
>> > +                result.pageNewCopy = null;
>> > +            }
>> > +            else
>> > +            {
>> > +                child = btree.copyOnWrite( child );
>> > +            }
>> >
>> >             // update children
>> > -            keys[index] = child.getLargestKey();
>> > -            btree.recordManager.update( recordId, this, this );
>> > +            pageNewCopy.keys[index] = child.getLargestKey();
>> > +            btree.recordManager.update( recordId, pageNewCopy, this );
>> >
>> >             if ( result.underflow )
>> >             {
>> > @@ -569,10 +596,11 @@ public class BPage<K, V> implements Seri
>> >                     throw new IllegalStateException( I18n.err(
>> > I18n.ERR_513, "1" ) );
>> >                 }
>> >
>> > -                if ( index < children.length - 1 )
>> > +                if ( index < pageNewCopy.children.length - 1 )
>> >                 {
>> >                     // exists greater brother page
>> > -                    BPage<K, V> brother = childBPage( index + 1 );
>> > +                    BPage<K, V> brother = pageNewCopy.childBPage( index
>> > + 1 );
>> > +                    brother = btree.copyOnWrite( brother );
>> >                     int bfirst = brother.first;
>> >
>> >                     if ( bfirst < half )
>> > @@ -606,12 +634,12 @@ public class BPage<K, V> implements Seri
>> >                         }
>> >
>> >                         // update child's largest key
>> > -                        keys[index] = child.getLargestKey();
>> > +                        pageNewCopy.keys[index] =
>> > child.getLargestKey();
>> >
>> >                         // no change in previous/next BPage
>> >
>> >                         // update BPages
>> > -                        btree.recordManager.update( recordId, this,
>> > this );
>> > +                        btree.recordManager.update( recordId,
>> > pageNewCopy, this );
>> >                         btree.recordManager.update( brother.recordId,
>> > brother, this );
>> >                         btree.recordManager.update( child.recordId,
>> > child, this );
>> >
>> > @@ -638,24 +666,25 @@ public class BPage<K, V> implements Seri
>> >                         btree.recordManager.update( brother.recordId,
>> > brother, this );
>> >
>> >                         // remove "child" from current BPage
>> > -                        if ( isLeaf )
>> > +                        if ( pageNewCopy.isLeaf )
>> >                         {
>> > -                            copyEntries( this, first, this, first + 1,
>> > index - first );
>> > -                            setEntry( this, first, null, null );
>> > +                            copyEntries( pageNewCopy,
>> > pageNewCopy.first, pageNewCopy, pageNewCopy.first + 1, index -
>> > pageNewCopy.first );
>> > +                            setEntry( pageNewCopy, pageNewCopy.first,
>> > null, null );
>> >                         }
>> >                         else
>> >                         {
>> > -                            copyChildren( this, first, this, first + 1,
>> > index - first );
>> > -                            setChild( this, first, null, -1 );
>> > +                            copyChildren( pageNewCopy,
>> > pageNewCopy.first, pageNewCopy, pageNewCopy.first + 1, index -
>> > pageNewCopy.first );
>> > +                            setChild( pageNewCopy, pageNewCopy.first,
>> > null, -1 );
>> >                         }
>> >
>> > -                        first += 1;
>> > -                        btree.recordManager.update( recordId, this,
>> > this );
>> > +                        pageNewCopy.first += 1;
>> > +                        btree.recordManager.update( recordId,
>> > pageNewCopy, this );
>> >
>> >                         // re-link previous and next BPages
>> >                         if ( child.previous != 0 )
>> >                         {
>> >                             BPage<K, V> prev = loadBPage( child.previous
>> > );
>> > +                            prev = btree.copyOnWrite( prev );
>> >                             prev.next = child.next;
>> >                             btree.recordManager.update( prev.recordId,
>> > prev, this );
>> >                         }
>> > @@ -663,6 +692,7 @@ public class BPage<K, V> implements Seri
>> >                         if ( child.next != 0 )
>> >                         {
>> >                             BPage<K, V> next = loadBPage( child.next );
>> > +                            next = btree.copyOnWrite( next );
>> >                             next.previous = child.previous;
>> >                             btree.recordManager.update( next.recordId,
>> > next, this );
>> >                         }
>> > @@ -674,7 +704,8 @@ public class BPage<K, V> implements Seri
>> >                 else
>> >                 {
>> >                     // page "brother" is before "child"
>> > -                    BPage<K, V> brother = childBPage( index - 1 );
>> > +                    BPage<K, V> brother = pageNewCopy.childBPage( index
>> > - 1 );
>> > +                    brother = btree.copyOnWrite( brother );
>> >                     int bfirst = brother.first;
>> >
>> >                     if ( bfirst < half )
>> > @@ -708,12 +739,12 @@ public class BPage<K, V> implements Seri
>> >                         }
>> >
>> >                         // update brother's largest key
>> > -                        keys[index - 1] = brother.getLargestKey();
>> > +                        pageNewCopy.keys[index - 1] =
>> > brother.getLargestKey();
>> >
>> >                         // no change in previous/next BPage
>> >
>> >                         // update BPages
>> > -                        btree.recordManager.update( recordId, this,
>> > this );
>> > +                        btree.recordManager.update( recordId,
>> > pageNewCopy, this );
>> >                         btree.recordManager.update( brother.recordId,
>> > brother, this );
>> >                         btree.recordManager.update( child.recordId,
>> > child, this );
>> >
>> > @@ -740,24 +771,25 @@ public class BPage<K, V> implements Seri
>> >                         btree.recordManager.update( child.recordId,
>> > child, this );
>> >
>> >                         // remove "brother" from current BPage
>> > -                        if ( isLeaf )
>> > +                        if ( pageNewCopy.isLeaf )
>> >                         {
>> > -                            copyEntries( this, first, this, first + 1,
>> > index - 1 - first );
>> > -                            setEntry( this, first, null, null );
>> > +                            copyEntries( pageNewCopy,
>> > pageNewCopy.first, pageNewCopy, pageNewCopy.first + 1, index - 1 -
>> > pageNewCopy.first );
>> > +                            setEntry( pageNewCopy, pageNewCopy.first,
>> > null, null );
>> >                         }
>> >                         else
>> >                         {
>> > -                            copyChildren( this, first, this, first + 1,
>> > index - 1 - first );
>> > -                            setChild( this, first, null, -1 );
>> > +                            copyChildren( pageNewCopy,
>> > pageNewCopy.first, pageNewCopy, pageNewCopy.first + 1, index - 1 -
>> > pageNewCopy.first );
>> > +                            setChild( pageNewCopy, pageNewCopy.first,
>> > null, -1 );
>> >                         }
>> >
>> > -                        first += 1;
>> > -                        btree.recordManager.update( recordId, this,
>> > this );
>> > +                        pageNewCopy.first += 1;
>> > +                        btree.recordManager.update( recordId,
>> > pageNewCopy, this );
>> >
>> >                         // re-link previous and next BPages
>> >                         if ( brother.previous != 0 )
>> >                         {
>> >                             BPage<K, V> prev = loadBPage(
>> > brother.previous );
>> > +                            prev = btree.copyOnWrite( prev );
>> >                             prev.next = brother.next;
>> >                             btree.recordManager.update( prev.recordId,
>> > prev, this );
>> >                         }
>> > @@ -765,6 +797,7 @@ public class BPage<K, V> implements Seri
>> >                         if ( brother.next != 0 )
>> >                         {
>> >                             BPage<K, V> next = loadBPage( brother.next
>> > );
>> > +                            next = btree.copyOnWrite( next );
>> >                             next.previous = brother.previous;
>> >                             btree.recordManager.update( next.recordId,
>> > next, this );
>> >                         }
>> > @@ -777,7 +810,8 @@ public class BPage<K, V> implements Seri
>> >         }
>> >
>> >         // underflow if page is more than half-empty
>> > -        result.underflow = first > half;
>> > +        result.underflow = pageNewCopy.first > half;
>> > +        result.pageNewCopy = pageNewCopy;
>> >
>> >         return result;
>> >     }
>> > @@ -1316,13 +1350,18 @@ public class BPage<K, V> implements Seri
>> >          * Existing value for the insertion key.
>> >          */
>> >         V existing;
>> > +
>> > +        /**
>> > +         * New version of the page doing the insert
>> > +         */
>> > +        BPage<K, V> pageNewCopy;
>> >     }
>> >
>> >     /** STATIC INNER CLASS
>> >      *  Result from remove() method call. If we had to removed a BPage,
>> >      *  it will be stored into the underflow field.
>> >      */
>> > -    static class RemoveResult<V>
>> > +    static class RemoveResult<K, V>
>> >     {
>> >         /**
>> >          * Set to true if underlying pages underflowed
>> > @@ -1333,6 +1372,12 @@ public class BPage<K, V> implements Seri
>> >          * Removed entry value
>> >          */
>> >         V value;
>> > +
>> > +        /**
>> > +         * New version of the page doing the remove
>> > +         */
>> > +        BPage<K, V> pageNewCopy;
>> > +
>> >     }
>> >
>> >     /** PRIVATE INNER CLASS
>> > @@ -1342,6 +1387,9 @@ public class BPage<K, V> implements Seri
>> >     {
>> >         /** Current page. */
>> >         private BPage<K, V> page;
>> > +
>> > +        /** Browsing action's context in case of a action capable
>> > record manager */
>> > +        ActionContext context;
>> >
>> >         /**
>> >          * Current index in the page.  The index positionned on the next
>> > @@ -1354,12 +1402,14 @@ public class BPage<K, V> implements Seri
>> >          * Create a browser.
>> >          *
>> >          * @param page Current page
>> > +         * @param context Action specific context. Not null if part of
>> > an action
>> >          * @param index Position of the next tuple to return.
>> >          */
>> > -        Browser( BPage<K, V> page, int index )
>> > +        Browser( BPage<K, V> page, int index, ActionContext context )
>> >         {
>> >             this.page = page;
>> >             this.index = index;
>> > +            this.context = context;
>> >         }
>> >
>> >
>> > @@ -1373,6 +1423,7 @@ public class BPage<K, V> implements Seri
>> >          */
>> >         public boolean getNext( Tuple<K, V> tuple ) throws IOException
>> >         {
>> > +            btree.setAsCurrentAction( context );
>> >             // First, check that we are within a page
>> >             if ( index < page.btree.pageSize )
>> >             {
>> > @@ -1402,6 +1453,7 @@ public class BPage<K, V> implements Seri
>> >
>> >         public boolean getPrevious( Tuple<K, V> tuple ) throws
>> > IOException
>> >         {
>> > +            btree.setAsCurrentAction( context );
>> >             if ( index == page.first )
>> >             {
>> >                 if ( page.previous != 0 )
>> > @@ -1422,6 +1474,12 @@ public class BPage<K, V> implements Seri
>> >
>> >             return true;
>> >         }
>> > +
>> > +        @Override
>> > +        public void close()
>> > +        {
>> > +            btree.endAction( context );
>> > +        }
>> >     }
>> >
>> >
>> >
>> > Modified:
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BTree.java
>> > URL:
>> > http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BTree.java?rev=1161416&r1=1161415&r2=1161416&view=diff
>> >
>> > ==============================================================================
>> > ---
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BTree.java
>> > (original)
>> > +++
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BTree.java
>> > Thu Aug 25 06:58:36 2011
>> > @@ -52,13 +52,23 @@ import java.io.IOException;
>> >  import java.io.ObjectInput;
>> >  import java.io.ObjectOutput;
>> >  import java.io.Serializable;
>> > +import java.io.ByteArrayInputStream;
>> > +import java.io.ByteArrayOutputStream;
>> > +import java.io.ObjectInputStream;
>> > +import java.io.ObjectOutputStream;
>> >  import java.util.Comparator;
>> >  import java.util.concurrent.atomic.AtomicInteger;
>> >
>> >  import jdbm.RecordManager;
>> > +import jdbm.ActionRecordManager;
>> >  import jdbm.helper.Serializer;
>> >  import jdbm.helper.Tuple;
>> >  import jdbm.helper.TupleBrowser;
>> > +import jdbm.helper.WrappedRuntimeException;
>> > +import jdbm.helper.ActionContext;
>> > +
>> > +import java.util.concurrent.locks.Lock;
>> > +import java.util.concurrent.locks.ReentrantLock;
>> >
>> >  import org.apache.directory.server.i18n.I18n;
>> >
>> > @@ -131,7 +141,13 @@ 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();
>> >
>> >     /**
>> >      * No-argument constructor used by serialization.
>> > @@ -220,8 +236,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 );
>> > +
>> > +        try
>> > +        {
>> > +            this.recordId = recordManager.insert( this );
>> > +        }
>> > +        catch ( IOException e )
>> > +        {
>> > +            abortedAction = true;
>> > +            this.abortAction( context );
>> > +            throw e;
>> > +        }
>> > +        finally
>> > +        {
>> > +            if ( !abortedAction )
>> > +                this.endAction( context );
>> > +        }
>> >     }
>> >
>> >
>> > @@ -268,7 +303,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,58 +315,88 @@ 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 );
>> > +
>> >
>> > -        if ( rootPage == null )
>> > -        {
>> > -            // 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;
>> > -        }
>> > -        else
>> > +        if ( !isActionCapable )
>> > +            bigLock.lock();
>> > +
>> > +        try
>> >         {
>> > -            BPage.InsertResult<K, V> insert = rootPage.insert(
>> > bTreeHeight, key, value, replace );
>> > -            boolean dirty = false;
>> > -
>> > -            if ( insert.overflow != null )
>> > +            BPage<K, V> rootPage = getRoot( false );
>> > +
>> > +            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;
>> > -            }
>> > -
>> > -            if ( insert.existing == null )
>> > -            {
>> > -                nbEntries.getAndIncrement();
>> > -                dirty = true;
>> > +                bTreeHeight = 1;
>> > +                nbEntries.set( 1 );
>> > +                recordManager.update( recordId, this );
>> > +
>> > +                return null;
>> >             }
>> > -
>> > -            if ( dirty )
>> > +            else
>> >             {
>> > -                recordManager.update( recordId, this );
>> > +                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;
>> > +                }
>> > +
>> > +                if ( insert.existing == null )
>> > +                {
>> > +                    nbEntries.getAndIncrement();
>> > +                    dirty = true;
>> > +                }
>> > +
>> > +                if ( dirty )
>> > +                {
>> > +                    recordManager.update( recordId, this );
>> > +                }
>> > +
>> > +                // insert might have returned an existing value
>> > +                return insert.existing;
>> >             }
>> > +        }
>> > +        catch ( IOException e )
>> > +        {
>> > +            abortedAction = true;
>> > +            this.abortAction( context );
>> > +            throw e;
>> > +        }
>> > +        finally
>> > +        {
>> > +            if ( !abortedAction )
>> > +                this.endAction( context );
>> >
>> > -            // insert might have returned an existing value
>> > -            return insert.existing;
>> > +            if ( !isActionCapable )
>> > +                bigLock.unlock();
>> >         }
>> > +
>> >     }
>> > +
>> >
>> >
>> >     /**
>> > @@ -341,52 +406,80 @@ 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 )
>> > -        {
>> > -            return null;
>> > -        }
>> > -
>> > -        boolean dirty = false;
>> > -        BPage.RemoveResult<V> remove = rootPage.remove( bTreeHeight,
>> > key );
>> > +        boolean abortedAction = false;
>> > +        ActionContext context = this.beginAction( false );
>> > +
>> > +        if ( !isActionCapable )
>> > +            bigLock.lock();
>> >
>> > -        if ( remove.underflow && rootPage.isEmpty() )
>> > +        try
>> >         {
>> > -            bTreeHeight -= 1;
>> > -            dirty = true;
>> >
>> > -            recordManager.delete( rootId );
>> > +            BPage<K, V> rootPage = getRoot( false );
>> >
>> > -            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 )
>> > +                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();
>> > +                }
>> > +            }
>> > +
>> > +            if ( remove.value != null )
>> >             {
>> > -                rootId = rootPage.childBPage( pageSize - 1
>> > ).getRecordId();
>> > +                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 +489,52 @@ 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 ( !isActionCapable )
>> > +            bigLock.lock();
>> >
>> > -        if ( rootPage == null )
>> > -        {
>> > -            return null;
>> > -        }
>> > -
>> > -        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 tuple.getValue();
>> > +                }
>> >             }
>> >             else
>> >             {
>> > -                return tuple.getValue();
>> > +                return null;
>> >             }
>> >         }
>> > -        else
>> > +        finally
>> >         {
>> > -            return null;
>> > +            if ( browser != null )
>> > +                browser.close();
>> > +
>> > +            if ( !isActionCapable )
>> > +                bigLock.unlock();
>> >         }
>> > +
>> >     }
>> >
>> >
>> > @@ -441,10 +546,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 +558,31 @@ public class BTree<K, V> implements Exte
>> >             return null;
>> >         }
>> >
>> > -        tuple = new Tuple<K, V>( null, null );
>> > -        browser = browse( key );
>> > +        if ( !isActionCapable )
>> > +            bigLock.lock();
>> >
>> > -        if ( browser.getNext( tuple ) )
>> > +        tuple = new Tuple<K, V>( null, null );
>> > +        try
>> >         {
>> > -            return tuple;
>> > +            browser = browse( key );
>> > +
>> > +            if ( browser.getNext( tuple ) )
>> > +            {
>> > +                return tuple;
>> > +            }
>> > +            else
>> > +            {
>> > +                return null;
>> > +            }
>> >         }
>> > -        else
>> > +        finally
>> >         {
>> > -            return null;
>> > +            if ( browser != null )
>> > +                browser.close();
>> > +
>> > +            if ( !isActionCapable )
>> > +                bigLock.unlock();
>> > +
>> >         }
>> >     }
>> >
>> > @@ -476,16 +596,26 @@ 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();
>> > -
>> > -        if ( rootPage == null )
>> > +        TupleBrowser<K, V> browser = null;
>> > +        ActionContext context = this.beginAction( true );
>> > +        try
>> >         {
>> > -            return new EmptyBrowser(){};
>> > +            BPage<K, V> rootPage = getRoot( true );
>> > +
>> > +            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();
>> >
>> >         return browser;
>> >     }
>> > @@ -503,19 +633,32 @@ 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 );
>> >
>> > -        if ( rootPage == null )
>> > +        try
>> >         {
>> > -            return new EmptyBrowser(){};
>> > +            BPage<K, V> rootPage = getRoot( true );
>> > +
>> > +            if ( rootPage == null )
>> > +            {
>> > +                this.endAction( context );
>> > +                return new EmptyBrowser(){};
>> > +            }
>> > +
>> > +            browser  = rootPage.find( rootPage.btree.bTreeHeight, key,
>> > context );
>> > +        }
>> > +        catch( IOException e )
>> > +        {
>> > +            this.abortAction( context );
>> > +            throw e;
>> >         }
>> > -
>> > -        TupleBrowser<K, V> browser = rootPage.find( bTreeHeight, key );
>> >
>> >         return browser;
>> >     }
>> > +
>> >
>> >
>> >     /**
>> > @@ -539,16 +682,27 @@ public class BTree<K, V> implements Exte
>> >     /**
>> >      * Return the root BPage<Object, Object>, or null if it doesn't
>> > exist.
>> >      */
>> > -    private BPage<K, V> getRoot() throws IOException
>> > +    private BPage<K, V> getRoot( boolean readOnlyAction ) throws
>> > IOException
>> >     {
>> > -        if ( rootId == 0 )
>> > +        BTree<K, V> bTreeCopy;
>> > +
>> > +        if ( readOnlyAction )
>> > +        {
>> > +            bTreeCopy = ( BTree<K, V> )recordManager.fetch( recordId );
>> > +        }
>> > +        else
>> > +        {
>> > +            bTreeCopy = this;
>> > +        }
>> > +
>> > +        if ( bTreeCopy.rootId == 0 )
>> >         {
>> >             return null;
>> >         }
>> >
>> > -        BPage<K, V> root = ( BPage<K, V> ) recordManager.fetch( rootId,
>> > bpageSerializer );
>> > -        root.setRecordId( rootId );
>> > -        root.btree = this;
>> > +        BPage<K, V> root = ( BPage<K, V> ) recordManager.fetch(
>> > bTreeCopy.rootId, bpageSerializer );
>> > +        root.setRecordId( bTreeCopy.rootId );
>> > +        root.btree = bTreeCopy;
>> >
>> >         return root;
>> >     }
>> > @@ -616,6 +770,115 @@ 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
>> > ).setCurrentActionContext( context );
>> > +        }
>> > +    }
>> > +
>> > +
>> > +    ActionContext beginAction( boolean readOnly )
>> > +    {
>> > +        ActionContext context = null;
>> > +        if ( isActionCapable )
>> > +        {
>> > +            context = ( ( ActionRecordManager )recordManager
>> > ).beginAction( readOnly );
>> > +            this.setAsCurrentAction( context );
>> > +        }
>> > +        return context;
>> > +    }
>> > +
>> > +
>> > +    void endAction( ActionContext context )
>> > +    {
>> > +        if ( context != null )
>> > +        {
>> > +            assert( isActionCapable );
>> > +            ( ( ActionRecordManager )recordManager ).endAction( context
>> > );
>> > +            this.unsetAsCurrentAction( context );
>> > +        }
>> > +    }
>> > +
>> > +    void abortAction( ActionContext context )
>> > +    {
>> > +        if ( context != null )
>> > +        {
>> > +            assert( isActionCapable );
>> > +            this.abortAction( context );
>> > +            ( ( ActionRecordManager )recordManager ).abortAction(
>> > context );
>> > +            this.unsetAsCurrentAction( context );
>> > +        }
>> > +
>> > +    }
>> > +
>> > +
>> > +    BPage<K,V> copyOnWrite( BPage<K,V> page) throws IOException
>> > +    {
>> > +        byte[] array;
>> > +        array = this.bpageSerializer.serialize( page );
>> > +        BPage<K,V> pageCopy = this.bpageSerializer.deserialize( array
>> > );
>> > +        pageCopy.recordId = page.recordId;
>> > +        pageCopy.btree = page.btree;
>> > +        return pageCopy;
>> > +    }
>> > +
>> > +    @SuppressWarnings("unchecked")
>> > +    private BTree<K,V> copyOnWrite() throws IOException
>> > +    {
>> > +        ObjectOutputStream out = null;
>> > +        ObjectInputStream in = null;
>> > +        ByteArrayOutputStream bout = null;
>> > +        ByteArrayInputStream bin = null;
>> > +
>> > +        BTree<K,V> tree;
>> > +
>> > +        try
>> > +        {
>> > +            bout = new ByteArrayOutputStream();
>> > +            out = new ObjectOutputStream( bout );
>> > +            out.writeObject( this );
>> > +            out.flush();
>> > +            byte[]  arr = bout.toByteArray();
>> > +            bin = new ByteArrayInputStream( arr );
>> > +            in =new ObjectInputStream( bin );
>> > +            tree = ( BTree<K, 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 tree;
>> > +    }
>> > +
>> > +
>> > +
>> >     public String toString()
>> >     {
>> >         StringBuilder sb = new StringBuilder();
>> >
>> > Modified:
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/TupleBrowser.java
>> > URL:
>> > http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/TupleBrowser.java?rev=1161416&r1=1161415&r2=1161416&view=diff
>> >
>> > ==============================================================================
>> > ---
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/TupleBrowser.java
>> > (original)
>> > +++
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/TupleBrowser.java
>> > Thu Aug 25 06:58:36 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/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java
>> > URL:
>> > http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java?rev=1161416&r1=1161415&r2=1161416&view=diff
>> >
>> > ==============================================================================
>> > ---
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java
>> > (original)
>> > +++
>> > directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java
>> > Thu Aug 25 06:58:36 2011
>> > @@ -52,6 +52,10 @@ import java.io.IOException;
>> >
>> >  import java.util.HashMap;
>> >  import java.util.Map;
>> > +import java.util.concurrent.ConcurrentHashMap;
>> > +import java.util.concurrent.locks.Lock;
>> > +import java.util.concurrent.locks.ReentrantLock;
>> > +import java.util.concurrent.locks.Condition;
>> >
>> >  import org.apache.directory.server.i18n.I18n;
>> >
>> > @@ -109,6 +113,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 +223,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 +246,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 +258,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 +291,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 +318,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 +333,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);
>> > +        }
>> >     }
>> >
>> >
>> > @@ -250,7 +362,6 @@ public final class BaseRecordManager
>> >         update( recid, obj, DefaultSerializer.INSTANCE );
>> >     }
>> >
>> > -
>> >     /**
>> >      * Updates a record using a custom serializer.
>> >      *
>> > @@ -259,33 +370,45 @@ 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
>> >     {
>> > -        checkIfClosed();
>> > +       LockElement element;
>> > +
>> > +       checkIfClosed();
>> >
>> >         if ( recid <= 0 )
>> >         {
>> >             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 +422,7 @@ public final class BaseRecordManager
>> >         return fetch( recid, DefaultSerializer.INSTANCE );
>> >     }
>> >
>> > -
>> > +
>> >     /**
>> >      * Fetches a record using a custom serializer.
>> >      *
>> > @@ -308,26 +431,41 @@ 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;
>> > -
>> > -        checkIfClosed();
>> > -
>> > +       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 ) ) );
>> > -
>> > -        if ( DEBUG )
>> > -        {
>> > -            System.out.println( "BaseRecordManager.fetch() recid " +
>> > recid + " length " + data.length ) ;
>> > -        }
>> > -        return serializer.deserialize( data );
>> > +
>> > +       element = this.beginIO(recid, IOType.READ_IO);
>> > +
>> > +       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
>> > +       {
>> > +               this.endIO(recid, element, IOType.READ_IO);
>> > +       }
>> > +
>> > +       return result;
>> > +
>> >     }
>> > +
>> >
>> >
>> >     /**
>> > @@ -347,7 +485,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 +498,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();
>> >
>> > @@ -411,7 +549,7 @@ public final class BaseRecordManager
>> >     /**
>> >      * Commit (make persistent) all changes since beginning of
>> > transaction.
>> >      */
>> > -    public synchronized void commit()
>> > +    public void commit()
>> >         throws IOException
>> >     {
>> >         checkIfClosed();
>> > @@ -423,7 +561,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 +616,125 @@ 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() );
>> > +    }
>> > +
>> >  }
>> >
>> >
>> >
>
>
>
> --
> Regards,
> Cordialement,
> Emmanuel Lécharny
> www.iktek.com
>
>
>
>
>

Mime
View raw message