directory-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Emmanuel Lecharny <elecha...@apache.org>
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:10:51 GMT
oops,


so I guess we have to go a step further with the patch. It might work for
JDBM tests (but as we only have a few of the base JDBM tests, it may be
giving the false feeling it's ok)

On Thu, Aug 25, 2011 at 3:09 PM, Emmanuel Lecharny <elecharny@apache.org>wrote:

> Same errors.
>
> I guess we have to go a
>
> On Thu, Aug 25, 2011 at 2: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?
>>
>> Regards,
>> Pierre-Arnaud
>>
>> 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
>>
>>
>>
>>
>>
>>
>
>
> --
> Regards,
> Cordialement,
> Emmanuel Lécharny
> www.iktek.com
>



-- 
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com

Mime
View raw message