Return-Path: X-Original-To: apmail-directory-dev-archive@www.apache.org Delivered-To: apmail-directory-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 270F470E7 for ; Thu, 25 Aug 2011 12:56:20 +0000 (UTC) Received: (qmail 60685 invoked by uid 500); 25 Aug 2011 12:56:20 -0000 Delivered-To: apmail-directory-dev-archive@directory.apache.org Received: (qmail 60617 invoked by uid 500); 25 Aug 2011 12:56:18 -0000 Mailing-List: contact dev-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Apache Directory Developers List" Delivered-To: mailing list dev@directory.apache.org Received: (qmail 60607 invoked by uid 99); 25 Aug 2011 12:56:17 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 25 Aug 2011 12:56:17 +0000 X-ASF-Spam-Status: No, hits=1.5 required=5.0 tests=FREEMAIL_FROM,HTML_MESSAGE,RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of pajbam@gmail.com designates 209.85.161.50 as permitted sender) Received: from [209.85.161.50] (HELO mail-fx0-f50.google.com) (209.85.161.50) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 25 Aug 2011 12:56:08 +0000 Received: by fxh2 with SMTP id 2so2019628fxh.37 for ; Thu, 25 Aug 2011 05:55:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=sender:from:mime-version:content-type:subject:date:in-reply-to:to :references:message-id:x-mailer; bh=yYYLcutcwQUg33sN9nCzyzZ+XHrB1hxZ2IAljnJo33M=; b=rfRzSXZ7VeyIkH5Dhk/JZk9lmlQB/4+vLgUdl7KgjLI8KOvvSrDkqBs1aC4QJrLEGw yTQ7LSEavwXhfeF1Uadi57zYjzGdD8rua0LZdfRWY0nrhPgbQERNWZtPo7Qcss2fZ8QY sLALd8M9k1AmCweTYcGEuYrCClOJVtAQ5CtMQ= Received: by 10.223.15.138 with SMTP id k10mr9194144faa.101.1314276945748; Thu, 25 Aug 2011 05:55:45 -0700 (PDT) Received: from [10.0.1.2] (def92-4-82-225-58-213.fbx.proxad.net [82.225.58.213]) by mx.google.com with ESMTPS id e2sm423552fah.1.2011.08.25.05.55.41 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 25 Aug 2011 05:55:43 -0700 (PDT) Sender: Pierre-Arnaud Marcelot From: Pierre-Arnaud Marcelot Mime-Version: 1.0 (Apple Message framework v1084) Content-Type: multipart/alternative; boundary=Apple-Mail-5-962290853 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 14:55:39 +0200 In-Reply-To: <5EE61EEB-5C7D-4B7E-806B-DC4688965E6A@marcelot.net> To: Apache Directory Developers List References: <20110825065836.CF49523889E7@eris.apache.org> <2D1D9DCF-31D4-4D80-AA71-8E038CE852D3@marcelot.net> <50506571-DCA7-4CFA-8510-86ECEF4B221A@marcelot.net> <5EE61EEB-5C7D-4B7E-806B-DC4688965E6A@marcelot.net> Message-Id: X-Mailer: Apple Mail (2.1084) --Apple-Mail-5-962290853 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=iso-8859-1 I'm getting the following test failures in jdbm-partition: > [INFO] = ------------------------------------------------------------------------ > [INFO] Building ApacheDS JDBM Partition 2.0.0-M3-SNAPSHOT > [INFO] = ------------------------------------------------------------------------ > [INFO]=20 > [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]=20 > [INFO] --- maven-remote-resources-plugin:1.2:process (default) @ = apacheds-jdbm-partition --- > [INFO]=20 > [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/res= ources > [INFO] Copying 3 resources > [INFO]=20 > [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/class= es > [INFO]=20 > [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]=20 > [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]=20 > [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/suref= ire-reports >=20 > ------------------------------------------------------- > T E S T S > ------------------------------------------------------- > Running = org.apache.directory.server.core.partition.impl.btree.jdbm.BTreeRedirectMa= rshallerTest > Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.211 = sec > Running = org.apache.directory.server.core.partition.impl.btree.jdbm.DupsContainerCu= rsorTest > 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.JdbmBrowserBugT= est > 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.JdbmMasterTable= Test > Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.553 = sec > Running = org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmRdnIndexTes= t > 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.JdbmTableNoDupl= icatesTest > 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.JdbmTableWithDu= plicatesTest > 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.KeyBTreeCursorT= est > 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.KeyTupleArrayCu= rsorTest > Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 = sec > Running = org.apache.directory.server.core.partition.impl.btree.jdbm.KeyTupleBTreeCu= rsorTest > 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.NoDupsCursorTes= t > 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.ServerEntrySeri= alizerTest > Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.466 = sec > Running = org.apache.directory.server.core.partition.impl.btree.jdbm.StringSerialize= rTest > 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 >=20 > Results : >=20 > Tests in error:=20 > = 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.j= dbm.DupsCursorTest) > = testNextDups(org.apache.directory.server.core.partition.impl.btree.jdbm.Du= psCursorTest) > = testPreviousDups(org.apache.directory.server.core.partition.impl.btree.jdb= m.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.btre= e.jdbm.DupsCursorTest) > = testLastOverDupLimit(org.apache.directory.server.core.partition.impl.btree= .jdbm.DupsCursorTest) > = testOverDupLimit(org.apache.directory.server.core.partition.impl.btree.jdb= m.DupsCursorTest) > = testUnderDupLimit(org.apache.directory.server.core.partition.impl.btree.jd= bm.DupsCursorTest) > = testBeforeAfterBelowDupLimit(org.apache.directory.server.core.partition.im= pl.btree.jdbm.DupsCursorTest) > = testBeforeAfterOverDupLimit(org.apache.directory.server.core.partition.imp= l.btree.jdbm.DupsCursorTest) > = testCloseReopen(org.apache.directory.server.core.partition.impl.btree.jdbm= .JdbmTableNoDuplicatesTest) > = testLoadData(org.apache.directory.server.core.partition.impl.btree.jdbm.Jd= bmTableNoDuplicatesTest) > = testNullOrEmptyKeyValue(org.apache.directory.server.core.partition.impl.bt= ree.jdbm.JdbmTableNoDuplicatesTest) > = testRemove(org.apache.directory.server.core.partition.impl.btree.jdbm.Jdbm= TableNoDuplicatesTest) > = testPut(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTab= leNoDuplicatesTest) > = testHas(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTab= leNoDuplicatesTest) > = testMiscellaneous(org.apache.directory.server.core.partition.impl.btree.jd= bm.JdbmTableWithDuplicatesTest) > = testCloseReopen(org.apache.directory.server.core.partition.impl.btree.jdbm= .JdbmTableWithDuplicatesTest) > = testLoadData(org.apache.directory.server.core.partition.impl.btree.jdbm.Jd= bmTableWithDuplicatesTest) > = testNullOrEmptyKeyValue(org.apache.directory.server.core.partition.impl.bt= ree.jdbm.JdbmTableWithDuplicatesTest) > = testRemove(org.apache.directory.server.core.partition.impl.btree.jdbm.Jdbm= TableWithDuplicatesTest) > = testPut(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTab= leWithDuplicatesTest) > = testHas(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTab= leWithDuplicatesTest) > = testDuplicateLimit(org.apache.directory.server.core.partition.impl.btree.j= dbm.JdbmTableWithDuplicatesTest) > = testNullOrEmptyKeyValueAfterDuplicateLimit(org.apache.directory.server.cor= e.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest) > = testNonEmptyCursor(org.apache.directory.server.core.partition.impl.btree.j= dbm.KeyTupleBTreeCursorTest) > = testOnTableWithMultipleEntries(org.apache.directory.server.core.partition.= impl.btree.jdbm.NoDupsCursorTest) >=20 > 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=FBt 2011, at 14:49, Pierre-Arnaud Marcelot wrote: > OK, >=20 > I moved the two test classes to their dedicated package 'jdbm.helper'. >=20 > And fixed the compilation failure in Maven (strangely it was fine in = Eclipse) by replacing this in: >> lrus =3D (LRUCache.LRU [] )new LRUCache.LRU[NUM_LRUS]; >=20 > by this: >> lrus =3D ( LRUCache.LRU[] ) new LRUCache.LRU[NUM_LRUS]; >=20 > Compilation is now fine in Eclipse *and* Maven. >=20 > Now, running all tests. >=20 > Regards, > Pierre-Arnaud >=20 >=20 > On 25 ao=FBt 2011, at 14:42, Pierre-Arnaud Marcelot wrote: >=20 >> I'm having trouble applying the 'jdbm1.diff' patch. >>=20 >> 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/hel= per/LRUCache.java:[118,28] ')' expected >>> [ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,29] ';' expected >>> [ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,33] illegal start of expression >>> [ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,34] ';' expected >>> [ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,36] illegal start of expression >>> [ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,37] ';' expected >>> [ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,54] not a statement >>=20 >>=20 >> More to come... >>=20 >> Regards, >> Pierre-Arnaud >>=20 >> On 25 ao=FBt 2011, at 13:58, Pierre-Arnaud Marcelot wrote: >>=20 >>> Sure, I'm on it. >>>=20 >>> Regards, >>> Pierre-Arnaud >>>=20 >>> On 25 ao=FBt 2011, at 13:41, Emmanuel Lecharny wrote: >>>=20 >>>> Strange... I did a pacth -p0 with your diff. >>>>=20 >>>> I may have not svn added the files. >>>>=20 >>>> i'm not connected right now (using a client internet connection, = will do that tonite >>>>=20 >>>> Or maybe Pierre-Arnaud can apply the patch, do a svn add of the = added files and commit ? >>>>=20 >>>> On Thu, Aug 25, 2011 at 9:41 AM, Selcuk AYA = wrote: >>>> Hi, >>>> there are alos a bunch of new filesn the patch I provided. Can you >>>> also add them to the branch? >>>>=20 >>>> 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 >>>>=20 >>>> regards, >>>> Selcuk >>>>=20 >>>> On Thu, Aug 25, 2011 at 9:58 AM, wrote: >>>> > Author: elecharny >>>> > Date: Thu Aug 25 06:58:36 2011 >>>> > New Revision: 1161416 >>>> > >>>> > URL: http://svn.apache.org/viewvc?rev=3D1161416&view=3Drev >>>> > Log: >>>> > applied Selcuk's patch >>>> > >>>> > Modified: >>>> > = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BP= age.java >>>> > = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BT= ree.java >>>> > = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/T= upleBrowser.java >>>> > = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/B= aseRecordManager.java >>>> > >>>> > Modified: = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BP= age.java >>>> > URL: = http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-jdbm/jdb= m/src/main/java/jdbm/btree/BPage.java?rev=3D1161416&r1=3D1161415&r2=3D1161= 416&view=3Ddiff >>>> > = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D >>>> > --- = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BP= age.java (original) >>>> > +++ = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BP= age.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 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 find( int height, K key ) throws = IOException >>>> > + TupleBrowser find( int height, K key, ActionContext = context ) throws IOException >>>> > { >>>> > int index =3D this.findChildren( key ); >>>> > >>>> > @@ -285,26 +287,27 @@ public class BPage 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 findFirst() throws IOException >>>> > + TupleBrowser findFirst(ActionContext context ) throws = IOException >>>> > { >>>> > if ( isLeaf ) >>>> > { >>>> > - return new Browser( this, first ); >>>> > + return new Browser( this, first, context ); >>>> > } >>>> > else >>>> > { >>>> > BPage child =3D childBPage( first ); >>>> > >>>> > - return child.findFirst(); >>>> > + return child.findFirst( context ); >>>> > } >>>> > } >>>> > >>>> > @@ -337,9 +340,12 @@ public class BPage implements Seri >>>> > >>>> > height -=3D 1; >>>> > >>>> > + BPage pageNewCopy =3D null; >>>> > if ( height =3D=3D 0 ) >>>> > { >>>> > + pageNewCopy =3D btree.copyOnWrite( this ); >>>> > result =3D new InsertResult(); >>>> > + result.pageNewCopy =3D pageNewCopy; >>>> > >>>> > // inserting on a leaf BPage >>>> > overflow =3D -1; >>>> > @@ -365,8 +371,8 @@ public class BPage implements Seri >>>> > >>>> > if ( replace ) >>>> > { >>>> > - values[index] =3D value; >>>> > - btree.recordManager.update( recordId, this, = this ); >>>> > + pageNewCopy.values[index] =3D value; >>>> > + btree.recordManager.update( recordId, = pageNewCopy, this ); >>>> > } >>>> > >>>> > // return the existing key >>>> > @@ -378,6 +384,11 @@ public class BPage implements Seri >>>> > // non-leaf BPage >>>> > BPage child =3D childBPage( index ); >>>> > result =3D child.insert( height, key, value, replace = ); >>>> > + if( result.pageNewCopy !=3D null) >>>> > + { >>>> > + child =3D result.pageNewCopy; >>>> > + result.pageNewCopy =3D null; >>>> > + } >>>> > >>>> > if ( result.existing !=3D null ) >>>> > { >>>> > @@ -393,6 +404,9 @@ public class BPage implements Seri >>>> > >>>> > // there was an overflow, we need to insert the = overflow page >>>> > // on this BPage >>>> > + pageNewCopy =3D btree.copyOnWrite( this ); >>>> > + result.pageNewCopy =3D pageNewCopy; >>>> > + >>>> > if ( DEBUG ) >>>> > { >>>> > System.out.println( "BPage.insert() Overflow = page: " + result.overflow.recordId ); >>>> > @@ -402,7 +416,7 @@ public class BPage implements Seri >>>> > overflow =3D result.overflow.recordId; >>>> > >>>> > // update child's largest key >>>> > - keys[index] =3D child.getLargestKey(); >>>> > + pageNewCopy.keys[index] =3D child.getLargestKey(); >>>> > >>>> > // clean result so we can reuse it >>>> > result.overflow =3D null; >>>> > @@ -410,24 +424,25 @@ public class BPage 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 =3D=3D 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 =3D btree.pageSize >> 1; >>>> > - BPage newPage =3D new BPage( btree, isLeaf = ); >>>> > + BPage newPage =3D new BPage( btree, = pageNewCopy.isLeaf ); >>>> > + >>>> > >>>> > if ( index < half ) >>>> > { >>>> > @@ -441,15 +456,15 @@ public class BPage implements Seri >>>> > >>>> > if ( height =3D=3D 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 implements Seri >>>> > >>>> > if ( height =3D=3D 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 =3D half - 1; >>>> > + pageNewCopy.first =3D half - 1; >>>> > >>>> > // nullify lower half of entries >>>> > - for ( int i =3D 0; i < first; i++ ) >>>> > + for ( int i =3D 0; i < pageNewCopy.first; i++ ) >>>> > { >>>> > if ( height =3D=3D 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 =3D previous; >>>> > - newPage.next =3D recordId; >>>> > + newPage.previous =3D pageNewCopy.previous; >>>> > + newPage.next =3D pageNewCopy.recordId; >>>> > >>>> > - if ( previous !=3D 0 ) >>>> > + if ( pageNewCopy.previous !=3D 0 ) >>>> > { >>>> > - BPage previousBPage =3D loadBPage( = previous ); >>>> > + BPage previousBPage =3D loadBPage( = pageNewCopy.previous ); >>>> > + previousBPage =3D btree.copyOnWrite( = previousBPage ); >>>> > previousBPage.next =3D newPage.recordId; >>>> > - btree.recordManager.update( previous, = previousBPage, this ); >>>> > + btree.recordManager.update( = pageNewCopy.previous, previousBPage, this ); >>>> > } >>>> > >>>> > - previous =3D newPage.recordId; >>>> > + pageNewCopy.previous =3D newPage.recordId; >>>> > } >>>> > >>>> > - btree.recordManager.update( recordId, this, this ); >>>> > + btree.recordManager.update( recordId, pageNewCopy, this = ); >>>> > btree.recordManager.update( newPage.recordId, newPage, = this ); >>>> > >>>> > result.overflow =3D newPage; >>>> > @@ -521,9 +537,9 @@ public class BPage implements Seri >>>> > * @param key Removal key >>>> > * @return Remove result object >>>> > */ >>>> > - RemoveResult remove( int height, K key ) throws = IOException >>>> > + RemoveResult remove( int height, K key ) throws = IOException >>>> > { >>>> > - RemoveResult result; >>>> > + RemoveResult result; >>>> > >>>> > int half =3D btree.pageSize / 2; >>>> > int index =3D findChildren( key ); >>>> > @@ -536,6 +552,7 @@ public class BPage implements Seri >>>> > >>>> > height -=3D 1; >>>> > >>>> > + BPage pageNewCopy =3D btree.copyOnWrite( this );; >>>> > if ( height =3D=3D 0 ) >>>> > { >>>> > // remove leaf entry >>>> > @@ -544,22 +561,32 @@ public class BPage implements Seri >>>> > throw new IllegalArgumentException( I18n.err( = I18n.ERR_514, key ) ); >>>> > } >>>> > >>>> > - result =3D new RemoveResult(); >>>> > - result.value =3D values[index]; >>>> > - removeEntry( this, index ); >>>> > + result =3D new RemoveResult(); >>>> > + result.value =3D 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 child =3D childBPage( index ); >>>> > result =3D child.remove( height, key ); >>>> > + >>>> > + if ( result.pageNewCopy !=3D null ) >>>> > + { >>>> > + child =3D result.pageNewCopy; >>>> > + result.pageNewCopy =3D null; >>>> > + } >>>> > + else >>>> > + { >>>> > + child =3D btree.copyOnWrite( child ); >>>> > + } >>>> > >>>> > // update children >>>> > - keys[index] =3D child.getLargestKey(); >>>> > - btree.recordManager.update( recordId, this, this ); >>>> > + pageNewCopy.keys[index] =3D child.getLargestKey(); >>>> > + btree.recordManager.update( recordId, pageNewCopy, = this ); >>>> > >>>> > if ( result.underflow ) >>>> > { >>>> > @@ -569,10 +596,11 @@ public class BPage 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 brother =3D childBPage( index + = 1 ); >>>> > + BPage brother =3D = pageNewCopy.childBPage( index + 1 ); >>>> > + brother =3D btree.copyOnWrite( brother ); >>>> > int bfirst =3D brother.first; >>>> > >>>> > if ( bfirst < half ) >>>> > @@ -606,12 +634,12 @@ public class BPage implements Seri >>>> > } >>>> > >>>> > // update child's largest key >>>> > - keys[index] =3D child.getLargestKey(); >>>> > + pageNewCopy.keys[index] =3D = 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 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 +=3D 1; >>>> > - btree.recordManager.update( recordId, = this, this ); >>>> > + pageNewCopy.first +=3D 1; >>>> > + btree.recordManager.update( recordId, = pageNewCopy, this ); >>>> > >>>> > // re-link previous and next BPages >>>> > if ( child.previous !=3D 0 ) >>>> > { >>>> > BPage prev =3D loadBPage( = child.previous ); >>>> > + prev =3D btree.copyOnWrite( prev ); >>>> > prev.next =3D child.next; >>>> > btree.recordManager.update( = prev.recordId, prev, this ); >>>> > } >>>> > @@ -663,6 +692,7 @@ public class BPage implements Seri >>>> > if ( child.next !=3D 0 ) >>>> > { >>>> > BPage next =3D loadBPage( = child.next ); >>>> > + next =3D btree.copyOnWrite( next ); >>>> > next.previous =3D child.previous; >>>> > btree.recordManager.update( = next.recordId, next, this ); >>>> > } >>>> > @@ -674,7 +704,8 @@ public class BPage implements Seri >>>> > else >>>> > { >>>> > // page "brother" is before "child" >>>> > - BPage brother =3D childBPage( index - = 1 ); >>>> > + BPage brother =3D = pageNewCopy.childBPage( index - 1 ); >>>> > + brother =3D btree.copyOnWrite( brother ); >>>> > int bfirst =3D brother.first; >>>> > >>>> > if ( bfirst < half ) >>>> > @@ -708,12 +739,12 @@ public class BPage implements Seri >>>> > } >>>> > >>>> > // update brother's largest key >>>> > - keys[index - 1] =3D = brother.getLargestKey(); >>>> > + pageNewCopy.keys[index - 1] =3D = 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 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 +=3D 1; >>>> > - btree.recordManager.update( recordId, = this, this ); >>>> > + pageNewCopy.first +=3D 1; >>>> > + btree.recordManager.update( recordId, = pageNewCopy, this ); >>>> > >>>> > // re-link previous and next BPages >>>> > if ( brother.previous !=3D 0 ) >>>> > { >>>> > BPage prev =3D loadBPage( = brother.previous ); >>>> > + prev =3D btree.copyOnWrite( prev ); >>>> > prev.next =3D brother.next; >>>> > btree.recordManager.update( = prev.recordId, prev, this ); >>>> > } >>>> > @@ -765,6 +797,7 @@ public class BPage implements Seri >>>> > if ( brother.next !=3D 0 ) >>>> > { >>>> > BPage next =3D loadBPage( = brother.next ); >>>> > + next =3D btree.copyOnWrite( next ); >>>> > next.previous =3D brother.previous; >>>> > btree.recordManager.update( = next.recordId, next, this ); >>>> > } >>>> > @@ -777,7 +810,8 @@ public class BPage implements Seri >>>> > } >>>> > >>>> > // underflow if page is more than half-empty >>>> > - result.underflow =3D first > half; >>>> > + result.underflow =3D pageNewCopy.first > half; >>>> > + result.pageNewCopy =3D pageNewCopy; >>>> > >>>> > return result; >>>> > } >>>> > @@ -1316,13 +1350,18 @@ public class BPage implements Seri >>>> > * Existing value for the insertion key. >>>> > */ >>>> > V existing; >>>> > + >>>> > + /** >>>> > + * New version of the page doing the insert >>>> > + */ >>>> > + BPage 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 >>>> > + static class RemoveResult >>>> > { >>>> > /** >>>> > * Set to true if underlying pages underflowed >>>> > @@ -1333,6 +1372,12 @@ public class BPage implements Seri >>>> > * Removed entry value >>>> > */ >>>> > V value; >>>> > + >>>> > + /** >>>> > + * New version of the page doing the remove >>>> > + */ >>>> > + BPage pageNewCopy; >>>> > + >>>> > } >>>> > >>>> > /** PRIVATE INNER CLASS >>>> > @@ -1342,6 +1387,9 @@ public class BPage implements Seri >>>> > { >>>> > /** Current page. */ >>>> > private BPage 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 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 page, int index ) >>>> > + Browser( BPage page, int index, ActionContext = context ) >>>> > { >>>> > this.page =3D page; >>>> > this.index =3D index; >>>> > + this.context =3D context; >>>> > } >>>> > >>>> > >>>> > @@ -1373,6 +1423,7 @@ public class BPage implements Seri >>>> > */ >>>> > public boolean getNext( Tuple 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 implements Seri >>>> > >>>> > public boolean getPrevious( Tuple tuple ) throws = IOException >>>> > { >>>> > + btree.setAsCurrentAction( context ); >>>> > if ( index =3D=3D page.first ) >>>> > { >>>> > if ( page.previous !=3D 0 ) >>>> > @@ -1422,6 +1474,12 @@ public class BPage implements Seri >>>> > >>>> > return true; >>>> > } >>>> > + >>>> > + @Override >>>> > + public void close() >>>> > + { >>>> > + btree.endAction( context ); >>>> > + } >>>> > } >>>> > >>>> > >>>> > >>>> > Modified: = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BT= ree.java >>>> > URL: = http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-jdbm/jdb= m/src/main/java/jdbm/btree/BTree.java?rev=3D1161416&r1=3D1161415&r2=3D1161= 416&view=3Ddiff >>>> > = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D >>>> > --- = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BT= ree.java (original) >>>> > +++ = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BT= ree.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 implements Exte >>>> > >>>> > /** Serializer used for BPages of this tree */ >>>> > private transient BPage bpageSerializer; >>>> > - >>>> > + >>>> > + /** TRUE if underlying record manager is snapshot capable */ >>>> > + private transient boolean isActionCapable; >>>> > + >>>> > + >>>> > + /** Big lock snychronizing all actions */ >>>> > + private transient Lock bigLock =3D new ReentrantLock(); >>>> > >>>> > /** >>>> > * No-argument constructor used by serialization. >>>> > @@ -220,8 +236,27 @@ public class BTree implements Exte >>>> > this.bpageSerializer =3D new BPage(); >>>> > this.bpageSerializer.btree =3D this; >>>> > this.nbEntries =3D new AtomicInteger( 0 ); >>>> > + >>>> > + this.isActionCapable =3D recordManager instanceof = ActionRecordManager; >>>> > >>>> > - this.recordId =3D recordManager.insert( this ); >>>> > + boolean abortedAction =3D false; >>>> > + ActionContext context =3D this.beginAction( false ); >>>> > + >>>> > + try >>>> > + { >>>> > + this.recordId =3D recordManager.insert( this ); >>>> > + } >>>> > + catch ( IOException e ) >>>> > + { >>>> > + abortedAction =3D true; >>>> > + this.abortAction( context ); >>>> > + throw e; >>>> > + } >>>> > + finally >>>> > + { >>>> > + if ( !abortedAction ) >>>> > + this.endAction( context ); >>>> > + } >>>> > } >>>> > >>>> > >>>> > @@ -268,7 +303,7 @@ public class BTree 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 =3D=3D null ) >>>> > { >>>> > @@ -280,58 +315,88 @@ public class BTree implements Exte >>>> > throw new IllegalArgumentException( I18n.err( = I18n.ERR_524 ) ); >>>> > } >>>> > >>>> > - BPage rootPage =3D getRoot(); >>>> > + >>>> > + boolean abortedAction =3D false; >>>> > + ActionContext context =3D this.beginAction( false ); >>>> > + >>>> > >>>> > - if ( rootPage =3D=3D null ) >>>> > - { >>>> > - // BTree is currently empty, create a new root BPage >>>> > - if ( DEBUG ) >>>> > - { >>>> > - System.out.println( "BTree.insert() new root = BPage" ); >>>> > - } >>>> > - >>>> > - rootPage =3D new BPage( this, key, value ); >>>> > - rootId =3D rootPage.getRecordId(); >>>> > - bTreeHeight =3D 1; >>>> > - nbEntries.set( 1 ); >>>> > - recordManager.update( recordId, this ); >>>> > - >>>> > - return null; >>>> > - } >>>> > - else >>>> > + if ( !isActionCapable ) >>>> > + bigLock.lock(); >>>> > + >>>> > + try >>>> > { >>>> > - BPage.InsertResult insert =3D rootPage.insert( = bTreeHeight, key, value, replace ); >>>> > - boolean dirty =3D false; >>>> > - >>>> > - if ( insert.overflow !=3D null ) >>>> > + BPage rootPage =3D getRoot( false ); >>>> > + >>>> > + if ( rootPage =3D=3D 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 =3D new BPage( this, rootPage, = insert.overflow ); >>>> > + rootPage =3D new BPage( this, key, value = ); >>>> > rootId =3D rootPage.getRecordId(); >>>> > - bTreeHeight +=3D 1; >>>> > - dirty =3D true; >>>> > - } >>>> > - >>>> > - if ( insert.existing =3D=3D null ) >>>> > - { >>>> > - nbEntries.getAndIncrement(); >>>> > - dirty =3D true; >>>> > + bTreeHeight =3D 1; >>>> > + nbEntries.set( 1 ); >>>> > + recordManager.update( recordId, this ); >>>> > + >>>> > + return null; >>>> > } >>>> > - >>>> > - if ( dirty ) >>>> > + else >>>> > { >>>> > - recordManager.update( recordId, this ); >>>> > + BPage.InsertResult insert =3D = rootPage.insert( bTreeHeight, key, value, replace ); >>>> > + if ( insert.pageNewCopy !=3D null ) >>>> > + rootPage =3D insert.pageNewCopy; >>>> > + >>>> > + boolean dirty =3D false; >>>> > + >>>> > + if ( insert.overflow !=3D 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 =3D new BPage( this, = rootPage, insert.overflow ); >>>> > + rootId =3D rootPage.getRecordId(); >>>> > + bTreeHeight +=3D 1; >>>> > + dirty =3D true; >>>> > + } >>>> > + >>>> > + if ( insert.existing =3D=3D null ) >>>> > + { >>>> > + nbEntries.getAndIncrement(); >>>> > + dirty =3D true; >>>> > + } >>>> > + >>>> > + if ( dirty ) >>>> > + { >>>> > + recordManager.update( recordId, this ); >>>> > + } >>>> > + >>>> > + // insert might have returned an existing value >>>> > + return insert.existing; >>>> > } >>>> > + } >>>> > + catch ( IOException e ) >>>> > + { >>>> > + abortedAction =3D 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 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 =3D=3D null ) >>>> > { >>>> > throw new IllegalArgumentException( I18n.err( = I18n.ERR_523 ) ); >>>> > } >>>> > - >>>> > - BPage rootPage =3D getRoot(); >>>> > + >>>> > >>>> > - if ( rootPage =3D=3D null ) >>>> > - { >>>> > - return null; >>>> > - } >>>> > - >>>> > - boolean dirty =3D false; >>>> > - BPage.RemoveResult remove =3D rootPage.remove( = bTreeHeight, key ); >>>> > + boolean abortedAction =3D false; >>>> > + ActionContext context =3D this.beginAction( false ); >>>> > + >>>> > + if ( !isActionCapable ) >>>> > + bigLock.lock(); >>>> > >>>> > - if ( remove.underflow && rootPage.isEmpty() ) >>>> > + try >>>> > { >>>> > - bTreeHeight -=3D 1; >>>> > - dirty =3D true; >>>> > >>>> > - recordManager.delete( rootId ); >>>> > + BPage rootPage =3D getRoot( false ); >>>> > >>>> > - if ( bTreeHeight =3D=3D 0 ) >>>> > + if ( rootPage =3D=3D null ) >>>> > { >>>> > - rootId =3D 0; >>>> > + return null; >>>> > } >>>> > - else >>>> > + >>>> > + boolean dirty =3D false; >>>> > + BPage.RemoveResult remove =3D rootPage.remove( = bTreeHeight, key ); >>>> > + if ( remove.pageNewCopy !=3D null ) >>>> > + rootPage =3D remove.pageNewCopy; >>>> > + >>>> > + if ( remove.underflow && rootPage.isEmpty() ) >>>> > + { >>>> > + bTreeHeight -=3D 1; >>>> > + dirty =3D true; >>>> > + >>>> > + recordManager.delete( rootId ); >>>> > + >>>> > + if ( bTreeHeight =3D=3D 0 ) >>>> > + { >>>> > + rootId =3D 0; >>>> > + } >>>> > + else >>>> > + { >>>> > + rootId =3D rootPage.childBPage( pageSize - 1 = ).getRecordId(); >>>> > + } >>>> > + } >>>> > + >>>> > + if ( remove.value !=3D null ) >>>> > { >>>> > - rootId =3D rootPage.childBPage( pageSize - 1 = ).getRecordId(); >>>> > + nbEntries.getAndDecrement(); >>>> > + dirty =3D true; >>>> > } >>>> > + >>>> > + if ( dirty ) >>>> > + { >>>> > + recordManager.update( recordId, this ); >>>> > + } >>>> > + >>>> > + return remove.value; >>>> > } >>>> > - >>>> > - if ( remove.value !=3D null ) >>>> > + catch ( IOException e ) >>>> > { >>>> > - nbEntries.getAndDecrement(); >>>> > - dirty =3D true; >>>> > + abortedAction =3D 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 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 browser =3D null; >>>> > + Tuple tuple =3D null; >>>> > + >>>> > if ( key =3D=3D null ) >>>> > { >>>> > throw new IllegalArgumentException( I18n.err( = I18n.ERR_523 ) ); >>>> > } >>>> > >>>> > - BPage rootPage =3D getRoot(); >>>> > + if ( !isActionCapable ) >>>> > + bigLock.lock(); >>>> > >>>> > - if ( rootPage =3D=3D null ) >>>> > - { >>>> > - return null; >>>> > - } >>>> > - >>>> > - Tuple tuple =3D new Tuple( null, null ); >>>> > - TupleBrowser browser =3D 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() ) !=3D = 0 ) >>>> > + try >>>> > + { >>>> > + tuple =3D new Tuple( null, null ); >>>> > + >>>> > + browser =3D 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() ) = !=3D 0 ) >>>> > + { >>>> > + return null; >>>> > + } >>>> > + else >>>> > + { >>>> > + return tuple.getValue(); >>>> > + } >>>> > } >>>> > else >>>> > { >>>> > - return tuple.getValue(); >>>> > + return null; >>>> > } >>>> > } >>>> > - else >>>> > + finally >>>> > { >>>> > - return null; >>>> > + if ( browser !=3D null ) >>>> > + browser.close(); >>>> > + >>>> > + if ( !isActionCapable ) >>>> > + bigLock.unlock(); >>>> > } >>>> > + >>>> > } >>>> > >>>> > >>>> > @@ -441,10 +546,10 @@ public class BTree implements Exte >>>> > * @return Value associated with the key, or a greater entry, = or null if no >>>> > * greater entry was found. >>>> > */ >>>> > - public synchronized Tuple findGreaterOrEqual( K key ) = throws IOException >>>> > + public Tuple findGreaterOrEqual( K key ) throws = IOException >>>> > { >>>> > Tuple tuple; >>>> > - TupleBrowser browser; >>>> > + TupleBrowser browser =3D null; >>>> > >>>> > if ( key =3D=3D null ) >>>> > { >>>> > @@ -453,16 +558,31 @@ public class BTree implements Exte >>>> > return null; >>>> > } >>>> > >>>> > - tuple =3D new Tuple( null, null ); >>>> > - browser =3D browse( key ); >>>> > + if ( !isActionCapable ) >>>> > + bigLock.lock(); >>>> > >>>> > - if ( browser.getNext( tuple ) ) >>>> > + tuple =3D new Tuple( null, null ); >>>> > + try >>>> > { >>>> > - return tuple; >>>> > + browser =3D browse( key ); >>>> > + >>>> > + if ( browser.getNext( tuple ) ) >>>> > + { >>>> > + return tuple; >>>> > + } >>>> > + else >>>> > + { >>>> > + return null; >>>> > + } >>>> > } >>>> > - else >>>> > + finally >>>> > { >>>> > - return null; >>>> > + if ( browser !=3D null ) >>>> > + browser.close(); >>>> > + >>>> > + if ( !isActionCapable ) >>>> > + bigLock.unlock(); >>>> > + >>>> > } >>>> > } >>>> > >>>> > @@ -476,16 +596,26 @@ public class BTree implements Exte >>>> > * >>>> > * @return Browser positionned at the beginning of the BTree. >>>> > */ >>>> > - public synchronized TupleBrowser browse() throws = IOException >>>> > + public TupleBrowser browse() throws IOException >>>> > { >>>> > - BPage rootPage =3D getRoot(); >>>> > - >>>> > - if ( rootPage =3D=3D null ) >>>> > + TupleBrowser browser =3D null; >>>> > + ActionContext context =3D this.beginAction( true ); >>>> > + try >>>> > { >>>> > - return new EmptyBrowser(){}; >>>> > + BPage rootPage =3D getRoot( true ); >>>> > + >>>> > + if ( rootPage =3D=3D null ) >>>> > + { >>>> > + this.endAction( context ); >>>> > + return new EmptyBrowser(){}; >>>> > + } >>>> > + browser =3D rootPage.findFirst( context ); >>>> > + } >>>> > + catch( IOException e ) >>>> > + { >>>> > + this.abortAction( context ); >>>> > + throw e; >>>> > } >>>> > - >>>> > - TupleBrowser browser =3D rootPage.findFirst(); >>>> > >>>> > return browser; >>>> > } >>>> > @@ -503,19 +633,32 @@ public class BTree implements Exte >>>> > * (Null is considered to be an "infinite" key) >>>> > * @return Browser positioned just before the given key. >>>> > */ >>>> > - public synchronized TupleBrowser browse( K key ) = throws IOException >>>> > + public TupleBrowser browse( K key ) throws IOException >>>> > { >>>> > - BPage rootPage =3D getRoot(); >>>> > + TupleBrowser browser =3D null; >>>> > + ActionContext context =3D this.beginAction( true ); >>>> > >>>> > - if ( rootPage =3D=3D null ) >>>> > + try >>>> > { >>>> > - return new EmptyBrowser(){}; >>>> > + BPage rootPage =3D getRoot( true ); >>>> > + >>>> > + if ( rootPage =3D=3D null ) >>>> > + { >>>> > + this.endAction( context ); >>>> > + return new EmptyBrowser(){}; >>>> > + } >>>> > + >>>> > + browser =3D rootPage.find( = rootPage.btree.bTreeHeight, key, context ); >>>> > + } >>>> > + catch( IOException e ) >>>> > + { >>>> > + this.abortAction( context ); >>>> > + throw e; >>>> > } >>>> > - >>>> > - TupleBrowser browser =3D rootPage.find( = bTreeHeight, key ); >>>> > >>>> > return browser; >>>> > } >>>> > + >>>> > >>>> > >>>> > /** >>>> > @@ -539,16 +682,27 @@ public class BTree implements Exte >>>> > /** >>>> > * Return the root BPage, or null if it = doesn't exist. >>>> > */ >>>> > - private BPage getRoot() throws IOException >>>> > + private BPage getRoot( boolean readOnlyAction ) throws = IOException >>>> > { >>>> > - if ( rootId =3D=3D 0 ) >>>> > + BTree bTreeCopy; >>>> > + >>>> > + if ( readOnlyAction ) >>>> > + { >>>> > + bTreeCopy =3D ( BTree )recordManager.fetch( = recordId ); >>>> > + } >>>> > + else >>>> > + { >>>> > + bTreeCopy =3D this; >>>> > + } >>>> > + >>>> > + if ( bTreeCopy.rootId =3D=3D 0 ) >>>> > { >>>> > return null; >>>> > } >>>> > >>>> > - BPage root =3D ( BPage ) = recordManager.fetch( rootId, bpageSerializer ); >>>> > - root.setRecordId( rootId ); >>>> > - root.btree =3D this; >>>> > + BPage root =3D ( BPage ) = recordManager.fetch( bTreeCopy.rootId, bpageSerializer ); >>>> > + root.setRecordId( bTreeCopy.rootId ); >>>> > + root.btree =3D bTreeCopy; >>>> > >>>> > return root; >>>> > } >>>> > @@ -616,6 +770,115 @@ public class BTree implements Exte >>>> > } >>>> > >>>> > >>>> > + void setAsCurrentAction( ActionContext context ) >>>> > + { >>>> > + if ( context !=3D null ) >>>> > + { >>>> > + assert( isActionCapable =3D=3D true ); >>>> > + ( ( ActionRecordManager )recordManager = ).setCurrentActionContext( context ); >>>> > + } >>>> > + } >>>> > + >>>> > + void unsetAsCurrentAction( ActionContext context ) >>>> > + { >>>> > + if ( context !=3D null ) >>>> > + { >>>> > + assert( isActionCapable =3D=3D true ); >>>> > + ( ( ActionRecordManager )recordManager = ).setCurrentActionContext( context ); >>>> > + } >>>> > + } >>>> > + >>>> > + >>>> > + ActionContext beginAction( boolean readOnly ) >>>> > + { >>>> > + ActionContext context =3D null; >>>> > + if ( isActionCapable ) >>>> > + { >>>> > + context =3D ( ( ActionRecordManager )recordManager = ).beginAction( readOnly ); >>>> > + this.setAsCurrentAction( context ); >>>> > + } >>>> > + return context; >>>> > + } >>>> > + >>>> > + >>>> > + void endAction( ActionContext context ) >>>> > + { >>>> > + if ( context !=3D null ) >>>> > + { >>>> > + assert( isActionCapable ); >>>> > + ( ( ActionRecordManager )recordManager ).endAction( = context ); >>>> > + this.unsetAsCurrentAction( context ); >>>> > + } >>>> > + } >>>> > + >>>> > + void abortAction( ActionContext context ) >>>> > + { >>>> > + if ( context !=3D null ) >>>> > + { >>>> > + assert( isActionCapable ); >>>> > + this.abortAction( context ); >>>> > + ( ( ActionRecordManager )recordManager = ).abortAction( context ); >>>> > + this.unsetAsCurrentAction( context ); >>>> > + } >>>> > + >>>> > + } >>>> > + >>>> > + >>>> > + BPage copyOnWrite( BPage page) throws IOException >>>> > + { >>>> > + byte[] array; >>>> > + array =3D this.bpageSerializer.serialize( page ); >>>> > + BPage pageCopy =3D = this.bpageSerializer.deserialize( array ); >>>> > + pageCopy.recordId =3D page.recordId; >>>> > + pageCopy.btree =3D page.btree; >>>> > + return pageCopy; >>>> > + } >>>> > + >>>> > + @SuppressWarnings("unchecked") >>>> > + private BTree copyOnWrite() throws IOException >>>> > + { >>>> > + ObjectOutputStream out =3D null; >>>> > + ObjectInputStream in =3D null; >>>> > + ByteArrayOutputStream bout =3D null; >>>> > + ByteArrayInputStream bin =3D null; >>>> > + >>>> > + BTree tree; >>>> > + >>>> > + try >>>> > + { >>>> > + bout =3D new ByteArrayOutputStream(); >>>> > + out =3D new ObjectOutputStream( bout ); >>>> > + out.writeObject( this ); >>>> > + out.flush(); >>>> > + byte[] arr =3D bout.toByteArray(); >>>> > + bin =3D new ByteArrayInputStream( arr ); >>>> > + in =3Dnew ObjectInputStream( bin ); >>>> > + tree =3D ( BTree )in.readObject(); >>>> > + } >>>> > + catch ( ClassNotFoundException e ) >>>> > + { >>>> > + throw new WrappedRuntimeException( e ); >>>> > + } >>>> > + finally >>>> > + { >>>> > + if ( bout !=3D null ) >>>> > + bout.close(); >>>> > + >>>> > + if ( out !=3D null ) >>>> > + out.close(); >>>> > + >>>> > + if ( bin !=3D null ) >>>> > + bin.close(); >>>> > + >>>> > + if ( in !=3D null ) >>>> > + in.close(); >>>> > + } >>>> > + >>>> > + return tree; >>>> > + } >>>> > + >>>> > + >>>> > + >>>> > public String toString() >>>> > { >>>> > StringBuilder sb =3D new StringBuilder(); >>>> > >>>> > Modified: = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/T= upleBrowser.java >>>> > URL: = http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-jdbm/jdb= m/src/main/java/jdbm/helper/TupleBrowser.java?rev=3D1161416&r1=3D1161415&r= 2=3D1161416&view=3Ddiff >>>> > = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D >>>> > --- = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/T= upleBrowser.java (original) >>>> > +++ = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/T= upleBrowser.java Thu Aug 25 06:58:36 2011 >>>> > @@ -73,4 +73,11 @@ public abstract class TupleBrowser >>>> > * no previous tuple. >>>> > */ >>>> > public abstract boolean getPrevious( Tuple 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/B= aseRecordManager.java >>>> > URL: = http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-jdbm/jdb= m/src/main/java/jdbm/recman/BaseRecordManager.java?rev=3D1161416&r1=3D1161= 415&r2=3D1161416&view=3Ddiff >>>> > = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D >>>> > --- = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/B= aseRecordManager.java (original) >>>> > +++ = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/B= aseRecordManager.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 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 =3D new ReentrantLock(); >>>> > + private Condition cv =3D 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 =3D true; >>>> > + } >>>> > + >>>> > + >>>> > + public void unsetWritten() >>>> > + { >>>> > + writer =3D 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 = lockElements; >>>> > >>>> > >>>> > /** >>>> > @@ -123,13 +223,14 @@ public final class BaseRecordManager >>>> > pageMgr =3D new PageManager( recordFile ); >>>> > physMgr =3D new PhysicalRowIdManager( pageMgr ); >>>> > logMgr =3D new LogicalRowIdManager( pageMgr ); >>>> > + lockElements =3D new ConcurrentHashMap(); >>>> > } >>>> > >>>> > >>>> > /** >>>> > * 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 <=3D 0 ) >>>> > @@ -231,10 +333,20 @@ public final class BaseRecordManager >>>> > System.out.println( "BaseRecordManager.delete() recid = " + recid ) ; >>>> > } >>>> > >>>> > - Location logRowId =3D new Location( recid ); >>>> > - Location physRowId =3D logMgr.fetch( logRowId ); >>>> > - physMgr.delete( physRowId ); >>>> > - logMgr.delete( logRowId ); >>>> > + >>>> > + element =3D this.beginIO(recid, IOType.WRITE_IO); >>>> > + >>>> > + try >>>> > + { >>>> > + Location logRowId =3D new Location( recid ); >>>> > + Location physRowId =3D 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 <=3D 0 ) >>>> > { >>>> > throw new IllegalArgumentException( I18n.err( = I18n.ERR_536, recid ) ); >>>> > } >>>> > >>>> > - Location logRecid =3D new Location( recid ); >>>> > - Location physRecid =3D logMgr.fetch( logRecid ); >>>> > - >>>> > - byte[] data =3D serializer.serialize( obj ); >>>> > - >>>> > - if ( DEBUG ) >>>> > - { >>>> > - System.out.println( "BaseRecordManager.update() = recid " + recid + " length " + data.length ) ; >>>> > - } >>>> > - >>>> > - Location newRecid =3D physMgr.update( physRecid, data, = 0, data.length ); >>>> > - >>>> > - if ( ! newRecid.equals( physRecid ) ) >>>> > - { >>>> > - logMgr.update( logRecid, newRecid ); >>>> > - } >>>> > + element =3D this.beginIO(recid, IOType.WRITE_IO); >>>> > + >>>> > + try >>>> > + { >>>> > + Location logRecid =3D new Location( recid ); >>>> > + Location physRecid =3D logMgr.fetch( logRecid ); >>>> > + >>>> > + byte[] data =3D serializer.serialize( obj ); >>>> > + >>>> > + if ( DEBUG ) >>>> > + { >>>> > + System.out.println( "BaseRecordManager.update() = recid " + recid + " length " + data.length ) ; >>>> > + } >>>> > + >>>> > + Location newRecid =3D 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 <=3D 0 ) >>>> > { >>>> > throw new IllegalArgumentException( I18n.err( = I18n.ERR_536, recid ) ); >>>> > } >>>> > - >>>> > - data =3D physMgr.fetch( logMgr.fetch( new Location( = recid ) ) ); >>>> > - >>>> > - if ( DEBUG ) >>>> > - { >>>> > - System.out.println( "BaseRecordManager.fetch() recid = " + recid + " length " + data.length ) ; >>>> > - } >>>> > - return serializer.deserialize( data ); >>>> > + >>>> > + element =3D this.beginIO(recid, IOType.READ_IO); >>>> > + >>>> > + try >>>> > + { >>>> > + byte[] data; >>>> > + >>>> > + data =3D physMgr.fetch( logMgr.fetch( new Location( = recid ) ) ); >>>> > + >>>> > + if ( DEBUG ) >>>> > + { >>>> > + System.out.println( "BaseRecordManager.fetch() = recid " + recid + " length " + data.length ) ; >>>> > + } >>>> > + result =3D 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 =3D false; >>>> > + LockElement element =3D null; >>>> > + >>>> > + // loop until we successfully verify that there is no = concurrent writer >>>> > +/* >>>> > + element =3D lockElements.get( recid ); >>>> > + do >>>> > + { >>>> > + if ( element =3D=3D null ) >>>> > + { >>>> > + element =3D new LockElement(); >>>> > + >>>> > + if ( io =3D=3D IOType.READ_IO ) >>>> > + element.bumpReaders(); >>>> > + else >>>> > + element.setWritten(); >>>> > + >>>> > + LockElement existingElement =3D = lockElements.putIfAbsent( recid, element ); >>>> > + >>>> > + if ( existingElement =3D=3D null ) >>>> > + lockVerified =3D true; >>>> > + else >>>> > + element =3D existingElement; >>>> > + } >>>> > + else >>>> > + { >>>> > + Lock lock =3D 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 =3D=3D IOType.READ_IO ) >>>> > + element.bumpReaders(); >>>> > + else >>>> > + element.setWritten(); >>>> > + lockVerified =3D true; >>>> > + } >>>> > + else >>>> > + { >>>> > + if ( io =3D=3D IOType.READ_IO ) >>>> > + element.bumpReaders(); >>>> > + else >>>> > + element.setWritten(); >>>> > + >>>> > + LockElement existingElement =3D = lockElements.get( recid ); >>>> > + >>>> > + if ( element !=3D existingElement ) >>>> > + element =3D existingElement; >>>> > + else >>>> > + lockVerified =3D 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 =3D element.getLock(); >>>> > + lock.lock(); >>>> > + >>>> > + if ( io =3D=3D 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 =3D=3D IOType.READ_IO ) >>>> > + return element.beingWritten(); >>>> > + else >>>> > + return ( element.anyReaders() || = element.beingWritten() ); >>>> > + } >>>> > + >>>> > } >>>> > >>>> > >>>> > >>>>=20 >>>>=20 >>>>=20 >>>> --=20 >>>> Regards, >>>> Cordialement, >>>> Emmanuel L=E9charny >>>> www.iktek.com >>>=20 >>=20 >=20 --Apple-Mail-5-962290853 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=iso-8859-1 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/res= ources
[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/class= es
[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/suref= ire-reports

-------------------------------------= ------------------
 T E S T = S
-------------------------------------------------------
<= div>Running = org.apache.directory.server.core.partition.impl.btree.jdbm.BTreeRedirectMa= rshallerTest
Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, = Time elapsed: 0.211 sec
Running = org.apache.directory.server.core.partition.impl.btree.jdbm.DupsContainerCu= rsorTest
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<= /div>
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.JdbmBrowserBugT= est
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.JdbmMasterTable= Test
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time = elapsed: 0.553 sec
Running = org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmRdnIndexTes= t
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.JdbmTableNoDupl= icatesTest
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.JdbmTableWithDu= plicatesTest
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.KeyBTreeCursorT= est
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.KeyTupleArrayCu= rsorTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, = Time elapsed: 0.005 sec
Running = org.apache.directory.server.core.partition.impl.btree.jdbm.KeyTupleBTreeCu= rsorTest
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.NoDupsCursorTes= t
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.ServerEntrySeri= alizerTest
Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, = Time elapsed: 0.466 sec
Running = org.apache.directory.server.core.partition.impl.btree.jdbm.StringSerialize= rTest
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.j= dbm.DupsCursorTest)
  = testNextDups(org.apache.directory.server.core.partition.impl.btree.jdbm.Du= psCursorTest)
  = testPreviousDups(org.apache.directory.server.core.partition.impl.btree.jdb= m.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.btre= e.jdbm.DupsCursorTest)
  = testLastOverDupLimit(org.apache.directory.server.core.partition.impl.btree= .jdbm.DupsCursorTest)
  = testOverDupLimit(org.apache.directory.server.core.partition.impl.btree.jdb= m.DupsCursorTest)
  = testUnderDupLimit(org.apache.directory.server.core.partition.impl.btree.jd= bm.DupsCursorTest)
  = testBeforeAfterBelowDupLimit(org.apache.directory.server.core.partition.im= pl.btree.jdbm.DupsCursorTest)
  = testBeforeAfterOverDupLimit(org.apache.directory.server.core.partition.imp= l.btree.jdbm.DupsCursorTest)
  = testCloseReopen(org.apache.directory.server.core.partition.impl.btree.jdbm= .JdbmTableNoDuplicatesTest)
  = testLoadData(org.apache.directory.server.core.partition.impl.btree.jdbm.Jd= bmTableNoDuplicatesTest)
  = testNullOrEmptyKeyValue(org.apache.directory.server.core.partition.impl.bt= ree.jdbm.JdbmTableNoDuplicatesTest)
  = testRemove(org.apache.directory.server.core.partition.impl.btree.jdbm.Jdbm= TableNoDuplicatesTest)
  = testPut(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTab= leNoDuplicatesTest)
  = testHas(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTab= leNoDuplicatesTest)
  = testMiscellaneous(org.apache.directory.server.core.partition.impl.btree.jd= bm.JdbmTableWithDuplicatesTest)
  = testCloseReopen(org.apache.directory.server.core.partition.impl.btree.jdbm= .JdbmTableWithDuplicatesTest)
  = testLoadData(org.apache.directory.server.core.partition.impl.btree.jdbm.Jd= bmTableWithDuplicatesTest)
  = testNullOrEmptyKeyValue(org.apache.directory.server.core.partition.impl.bt= ree.jdbm.JdbmTableWithDuplicatesTest)
  = testRemove(org.apache.directory.server.core.partition.impl.btree.jdbm.Jdbm= TableWithDuplicatesTest)
  = testPut(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTab= leWithDuplicatesTest)
  = testHas(org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmTab= leWithDuplicatesTest)
  = testDuplicateLimit(org.apache.directory.server.core.partition.impl.btree.j= dbm.JdbmTableWithDuplicatesTest)
  = testNullOrEmptyKeyValueAfterDuplicateLimit(org.apache.directory.server.cor= e.partition.impl.btree.jdbm.JdbmTableWithDuplicatesTest)
  = testNonEmptyCursor(org.apache.directory.server.core.partition.impl.btree.j= dbm.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=FBt 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 =3D = (LRUCache<K,V>.LRU [] )new = LRUCache.LRU[NUM_LRUS];
by = this:
lrus =3D ( 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=FBt 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/hel= per/LRUCache.java:[118,28] ')' expected
[ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,29] ';' expected
[ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,33] illegal start of expression
[ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,34] ';' expected
[ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,36] illegal start of expression
[ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,37] ';' expected
[ERROR] = /Users/pajbam/Development/Apache/apacheds-jdbm/jdbm/src/main/java/jdbm/hel= per/LRUCache.java:[118,54] not a = statement

More to = come...

Regards,
Pierre-Arnaud

On 25 ao=FBt 2011, at 13:58, Pierre-Arnaud Marcelot = wrote:

Sure, I'm on = it.

Regards,
Pierre-Arnaud

On 25 ao=FBt 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=3D1161416&view=3Dre= v
> Log:
> applied Selcuk's patch
>
> Modified:
>   =  directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/bt= ree/BPage.java
>   =  directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/bt= ree/BTree.java
>   =  directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/he= lper/TupleBrowser.java
>   =  directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/re= cman/BaseRecordManager.java
>
> Modified: = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BP= age.java
> URL: http://svn.apache.org/viewvc/directory/apacheds/branches= /apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BPage.java?rev=3D1161416&= r1=3D1161415&r2=3D1161416&view=3Ddiff
> = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D
> --- = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BP= age.java (original)
> +++ = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BP= age.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 =3D 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 =3D= childBPage( first );
>
> -            return = child.findFirst();
> +            return child.findFirst( = context );
>         }
>     }
>
> @@ -337,9 +340,12 @@ public class BPage<K, V> implements = Seri
>
>         height -=3D 1;
>
> +        BPage<K,V> pageNewCopy =3D = null;
>         if ( height =3D=3D 0 )
>         {
> +            pageNewCopy =3D = btree.copyOnWrite( this );
>             result =3D new = InsertResult<K, V>();
> +            result.pageNewCopy =3D = pageNewCopy;
>
>             // inserting on a leaf = BPage
>             overflow =3D -1;
> @@ -365,8 +371,8 @@ public class BPage<K, V> implements = Seri
>
>                 if ( = replace )
>                 {
> -                   =  values[index] =3D value;
> -                   =  btree.recordManager.update( recordId, this, this );
> +                   =  pageNewCopy.values[index] =3D 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 =3D= childBPage( index );
>             result =3D child.insert( = height, key, value, replace );
> +            if( result.pageNewCopy = !=3D null)
> +            {
> +                child =3D = result.pageNewCopy;
> +               =  result.pageNewCopy =3D null;
> +            }
>
>             if ( result.existing !=3D = 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 =3D = btree.copyOnWrite( this );
> +            result.pageNewCopy =3D = 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 =3D = result.overflow.recordId;
>
>             // update child's largest = key
> -            keys[index] =3D = child.getLargestKey();
> +            pageNewCopy.keys[index] = =3D child.getLargestKey();
>
>             // clean result so we can = reuse it
>             result.overflow =3D = 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 =3D=3D 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 =3D btree.pageSize >> = 1;
> -        BPage<K, V> newPage =3D new = BPage<K, V>( btree, isLeaf );
> +        BPage<K, V> newPage =3D new = BPage<K, V>( btree, pageNewCopy.isLeaf );
> +
>
>         if ( index < half )
>         {
> @@ -441,15 +456,15 @@ public class BPage<K, V> implements = Seri
>
>             if ( height =3D=3D 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 =3D=3D 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 =3D half - 1;
> +        pageNewCopy.first =3D half - 1;
>
>         // nullify lower half of entries
> -        for ( int i =3D 0; i < first; i++ = )
> +        for ( int i =3D 0; i < = pageNewCopy.first; i++ )
>         {
>             if ( height =3D=3D 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 =3D = previous;
> -            newPage.next =3D = recordId;
> +            newPage.previous =3D = pageNewCopy.previous;
> +            newPage.next =3D = pageNewCopy.recordId;
>
> -            if ( previous !=3D 0 = )
> +            if ( = pageNewCopy.previous !=3D 0 )
>             {
> -               =  BPage<K, V> previousBPage =3D loadBPage( previous );
> +               =  BPage<K, V> previousBPage =3D loadBPage( = pageNewCopy.previous );
> +               =  previousBPage =3D btree.copyOnWrite( previousBPage );
>                 = previousBPage.next =3D newPage.recordId;
> -               =  btree.recordManager.update( previous, previousBPage, this );
> +               =  btree.recordManager.update( pageNewCopy.previous, previousBPage, = this );
>             }
>
> -            previous =3D = newPage.recordId;
> +            pageNewCopy.previous =3D = newPage.recordId;
>         }
>
> -        btree.recordManager.update( recordId, = this, this );
> +        btree.recordManager.update( recordId, = pageNewCopy, this );
>         btree.recordManager.update( = newPage.recordId, newPage, this );
>
>         result.overflow =3D 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 =3D btree.pageSize / 2;
>         int index =3D findChildren( key );
> @@ -536,6 +552,7 @@ public class BPage<K, V> implements = Seri
>
>         height -=3D 1;
>
> +        BPage<K,V> pageNewCopy =3D = btree.copyOnWrite( this );;
>         if ( height =3D=3D 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 =3D new = RemoveResult<V>();
> -            result.value =3D = values[index];
> -            removeEntry( this, index = );
> +            result =3D new = RemoveResult<K, V>();
> +            result.value =3D = 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 =3D= childBPage( index );
>             result =3D child.remove( = height, key );
> +
> +            if ( result.pageNewCopy = !=3D null )
> +            {
> +                child =3D = result.pageNewCopy;
> +               =  result.pageNewCopy =3D null;
> +            }
> +            else
> +            {
> +                child =3D = btree.copyOnWrite( child );
> +            }
>
>             // update children
> -            keys[index] =3D = child.getLargestKey();
> -           =  btree.recordManager.update( recordId, this, this );
> +            pageNewCopy.keys[index] = =3D 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 =3D childBPage( index + 1 );
> +                   =  BPage<K, V> brother =3D pageNewCopy.childBPage( index + 1 = );
> +                   =  brother =3D btree.copyOnWrite( brother );
>                   =   int bfirst =3D brother.first;
>
>                   =   if ( bfirst < half )
> @@ -606,12 +634,12 @@ public class BPage<K, V> implements = Seri
>                   =       }
>
>                   =       // update child's largest key
> -                   =      keys[index] =3D child.getLargestKey();
> +                   =      pageNewCopy.keys[index] =3D = 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 +=3D 1;
> -                   =      btree.recordManager.update( recordId, this, this = );
> +                   =      pageNewCopy.first +=3D 1;
> +                   =      btree.recordManager.update( recordId, pageNewCopy, = this );
>
>                   =       // re-link previous and next BPages
>                   =       if ( child.previous !=3D 0 )
>                   =       {
>                   =           BPage<K, V> prev =3D loadBPage( = child.previous );
> +                   =          prev =3D btree.copyOnWrite( prev = );
>                   =           prev.next =3D child.next;
>                   =           btree.recordManager.update( = prev.recordId, prev, this );
>                   =       }
> @@ -663,6 +692,7 @@ public class BPage<K, V> implements = Seri
>                   =       if ( child.next !=3D 0 )
>                   =       {
>                   =           BPage<K, V> next =3D loadBPage( = child.next );
> +                   =          next =3D btree.copyOnWrite( next = );
>                   =           next.previous =3D 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 =3D childBPage( index - 1 );
> +                   =  BPage<K, V> brother =3D pageNewCopy.childBPage( index - 1 = );
> +                   =  brother =3D btree.copyOnWrite( brother );
>                   =   int bfirst =3D brother.first;
>
>                   =   if ( bfirst < half )
> @@ -708,12 +739,12 @@ public class BPage<K, V> implements = Seri
>                   =       }
>
>                   =       // update brother's largest key
> -                   =      keys[index - 1] =3D brother.getLargestKey();
> +                   =      pageNewCopy.keys[index - 1] =3D = 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 +=3D 1;
> -                   =      btree.recordManager.update( recordId, this, this = );
> +                   =      pageNewCopy.first +=3D 1;
> +                   =      btree.recordManager.update( recordId, pageNewCopy, = this );
>
>                   =       // re-link previous and next BPages
>                   =       if ( brother.previous !=3D 0 )
>                   =       {
>                   =           BPage<K, V> prev =3D loadBPage( = brother.previous );
> +                   =          prev =3D btree.copyOnWrite( prev = );
>                   =           prev.next =3D brother.next;
>                   =           btree.recordManager.update( = prev.recordId, prev, this );
>                   =       }
> @@ -765,6 +797,7 @@ public class BPage<K, V> implements = Seri
>                   =       if ( brother.next !=3D 0 )
>                   =       {
>                   =           BPage<K, V> next =3D loadBPage( = brother.next );
> +                   =          next =3D btree.copyOnWrite( next = );
>                   =           next.previous =3D = 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 =3D first > = half;
> +        result.underflow =3D pageNewCopy.first = > half;
> +        result.pageNewCopy =3D = 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 =3D page;
>             this.index =3D index;
> +            this.context =3D = 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 =3D=3D = page.first )
>             {
>                 if ( = page.previous !=3D 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/BT= ree.java
> URL: http://svn.apache.org/viewvc/directory/apacheds/branches= /apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BTree.java?rev=3D1161416&= r1=3D1161415&r2=3D1161416&view=3Ddiff
> = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D
> --- = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BT= ree.java (original)
> +++ = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/btree/BT= ree.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 =3D new = ReentrantLock();
>
>     /**
>      * No-argument constructor used by = serialization.
> @@ -220,8 +236,27 @@ public class BTree<K, V> implements = Exte
>         this.bpageSerializer =3D new = BPage<K, V>();
>         this.bpageSerializer.btree =3D = this;
>         this.nbEntries =3D new AtomicInteger( 0 = );
> +
> +        this.isActionCapable =3D recordManager = instanceof ActionRecordManager;
>
> -        this.recordId =3D = recordManager.insert( this );
> +        boolean abortedAction =3D false;
> +        ActionContext context =3D = this.beginAction( false );
> +
> +        try
> +        {
> +            this.recordId =3D = recordManager.insert( this );
> +        }
> +        catch ( IOException e )
> +        {
> +            abortedAction =3D = 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 =3D=3D null )
>         {
> @@ -280,58 +315,88 @@ public class BTree<K, V> implements = Exte
>             throw new = IllegalArgumentException( I18n.err( I18n.ERR_524 ) );
>         }
>
> -        BPage<K, V> rootPage =3D = getRoot();
> +
> +        boolean abortedAction =3D false;
> +        ActionContext context  =3D = this.beginAction( false );
> +
>
> -        if ( rootPage =3D=3D null )
> -        {
> -            // BTree is currently = empty, create a new root BPage
> -            if ( DEBUG )
> -            {
> -               =  System.out.println( "BTree.insert() new root BPage" );
> -            }
> -
> -            rootPage =3D new = BPage<K, V>( this, key, value );
> -            rootId =3D = rootPage.getRecordId();
> -            bTreeHeight =3D 1;
> -            nbEntries.set( 1 );
> -            recordManager.update( = recordId, this );
> -
> -            return null;
> -        }
> -        else
> +        if ( !isActionCapable )
> +            bigLock.lock();
> +
> +        try
>         {
> -            BPage.InsertResult<K, = V> insert =3D rootPage.insert( bTreeHeight, key, value, replace = );
> -            boolean dirty =3D = false;
> -
> -            if ( insert.overflow !=3D = null )
> +            BPage<K, V> = rootPage =3D getRoot( false );
> +
> +            if ( rootPage =3D=3D = 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 =3D= new BPage<K, V>( this, rootPage, insert.overflow );
> +                rootPage =3D= new BPage<K, V>( this, key, value );
>                 rootId =3D = rootPage.getRecordId();
> -               =  bTreeHeight +=3D 1;
> -                dirty =3D = true;
> -            }
> -
> -            if ( insert.existing =3D=3D= null )
> -            {
> -               =  nbEntries.getAndIncrement();
> -                dirty =3D = true;
> +               =  bTreeHeight =3D 1;
> +               =  nbEntries.set( 1 );
> +               =  recordManager.update( recordId, this );
> +
> +                return = null;
>             }
> -
> -            if ( dirty )
> +            else
>             {
> -               =  recordManager.update( recordId, this );
> +               =  BPage.InsertResult<K, V> insert =3D rootPage.insert( = bTreeHeight, key, value, replace );
> +                if ( = insert.pageNewCopy !=3D null )
> +                   =  rootPage =3D insert.pageNewCopy;
> +
> +                boolean = dirty =3D false;
> +
> +                if ( = insert.overflow !=3D 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 =3D new BPage<K, V>( this, rootPage, = insert.overflow );
> +                   =  rootId =3D rootPage.getRecordId();
> +                   =  bTreeHeight +=3D 1;
> +                   =  dirty =3D true;
> +                }
> +
> +                if ( = insert.existing =3D=3D null )
> +                {
> +                   =  nbEntries.getAndIncrement();
> +                   =  dirty =3D true;
> +                }
> +
> +                if ( dirty = )
> +                {
> +                   =  recordManager.update( recordId, this );
> +                }
> +
> +                // insert = might have returned an existing value
> +                return = insert.existing;
>             }
> +        }
> +        catch ( IOException e )
> +        {
> +            abortedAction =3D = 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 =3D=3D null )
>         {
>             throw new = IllegalArgumentException( I18n.err( I18n.ERR_523 ) );
>         }
> -
> -        BPage<K, V> rootPage =3D = getRoot();
> +
>
> -        if ( rootPage =3D=3D null )
> -        {
> -            return null;
> -        }
> -
> -        boolean dirty =3D false;
> -        BPage.RemoveResult<V> remove =3D = rootPage.remove( bTreeHeight, key );
> +        boolean abortedAction =3D false;
> +        ActionContext context =3D = this.beginAction( false );
> +
> +        if ( !isActionCapable )
> +            bigLock.lock();
>
> -        if ( remove.underflow && = rootPage.isEmpty() )
> +        try
>         {
> -            bTreeHeight -=3D 1;
> -            dirty =3D true;
>
> -            recordManager.delete( = rootId );
> +            BPage<K, V> = rootPage =3D getRoot( false );
>
> -            if ( bTreeHeight =3D=3D = 0 )
> +            if ( rootPage =3D=3D = null )
>             {
> -                rootId =3D = 0;
> +                return = null;
>             }
> -            else
> +
> +            boolean dirty =3D = false;
> +            BPage.RemoveResult<K, = V> remove =3D rootPage.remove( bTreeHeight, key );
> +            if ( remove.pageNewCopy = !=3D null )
> +                rootPage =3D= remove.pageNewCopy;
> +
> +            if ( remove.underflow = && rootPage.isEmpty() )
> +            {
> +               =  bTreeHeight -=3D 1;
> +                dirty =3D = true;
> +
> +               =  recordManager.delete( rootId );
> +
> +                if ( = bTreeHeight =3D=3D 0 )
> +                {
> +                   =  rootId =3D 0;
> +                }
> +                else
> +                {
> +                   =  rootId =3D rootPage.childBPage( pageSize - 1 ).getRecordId();
> +                }
> +            }
> +
> +            if ( remove.value !=3D = null )
>             {
> -                rootId =3D = rootPage.childBPage( pageSize - 1 ).getRecordId();
> +               =  nbEntries.getAndDecrement();
> +                dirty =3D = true;
>             }
> +
> +            if ( dirty )
> +            {
> +               =  recordManager.update( recordId, this );
> +            }
> +
> +            return remove.value;
>         }
> -
> -        if ( remove.value !=3D null )
> +        catch ( IOException e )
>         {
> -           =  nbEntries.getAndDecrement();
> -            dirty =3D true;
> +            abortedAction =3D = 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 =3D = null;
> +        Tuple<K, V> tuple =3D null;
> +
>         if ( key =3D=3D null )
>         {
>             throw new = IllegalArgumentException( I18n.err( I18n.ERR_523 ) );
>         }
>
> -        BPage<K, V> rootPage =3D = getRoot();
> +        if ( !isActionCapable )
> +            bigLock.lock();
>
> -        if ( rootPage =3D=3D null )
> -        {
> -            return null;
> -        }
> -
> -        Tuple<K, V> tuple =3D new = Tuple<K, V>( null, null );
> -        TupleBrowser<K, V> browser =3D = 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() ) !=3D 0 )
> +        try
> +        {
> +            tuple =3D new = Tuple<K, V>( null, null );
> +
> +            browser =3D 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() ) !=3D 0 )
> +                {
> +                   =  return null;
> +                }
> +                else
> +                {
> +                   =  return tuple.getValue();
> +                }
>             }
>             else
>             {
> -                return = tuple.getValue();
> +                return = null;
>             }
>         }
> -        else
> +        finally
>         {
> -            return null;
> +            if ( browser !=3D 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 =3D = null;
>
>         if ( key =3D=3D null )
>         {
> @@ -453,16 +558,31 @@ public class BTree<K, V> implements = Exte
>             return null;
>         }
>
> -        tuple =3D new Tuple<K, V>( null, = null );
> -        browser =3D browse( key );
> +        if ( !isActionCapable )
> +            bigLock.lock();
>
> -        if ( browser.getNext( tuple ) )
> +        tuple =3D new Tuple<K, V>( null, = null );
> +        try
>         {
> -            return tuple;
> +            browser =3D browse( key = );
> +
> +            if ( browser.getNext( = tuple ) )
> +            {
> +                return = tuple;
> +            }
> +            else
> +            {
> +                return = null;
> +            }
>         }
> -        else
> +        finally
>         {
> -            return null;
> +            if ( browser !=3D 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 =3D = getRoot();
> -
> -        if ( rootPage =3D=3D null )
> +        TupleBrowser<K, V> browser =3D = null;
> +        ActionContext context =3D = this.beginAction( true );
> +        try
>         {
> -            return new = EmptyBrowser(){};
> +            BPage<K, V> = rootPage =3D getRoot( true );
> +
> +            if ( rootPage =3D=3D = null )
> +            {
> +               =  this.endAction( context );
> +                return new = EmptyBrowser(){};
> +            }
> +            browser =3D = rootPage.findFirst( context );
> +        }
> +        catch( IOException e )
> +        {
> +            this.abortAction( = context );
> +            throw e;
>         }
> -
> -        TupleBrowser<K, V> browser =3D = 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 =3D = getRoot();
> +        TupleBrowser<K, V> browser =3D = null;
> +        ActionContext context =3D = this.beginAction( true );
>
> -        if ( rootPage =3D=3D null )
> +        try
>         {
> -            return new = EmptyBrowser(){};
> +            BPage<K, V> = rootPage =3D getRoot( true );
> +
> +            if ( rootPage =3D=3D = null )
> +            {
> +               =  this.endAction( context );
> +                return new = EmptyBrowser(){};
> +            }
> +
> +            browser  =3D = rootPage.find( rootPage.btree.bTreeHeight, key, context );
> +        }
> +        catch( IOException e )
> +        {
> +            this.abortAction( = context );
> +            throw e;
>         }
> -
> -        TupleBrowser<K, V> browser =3D = 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 =3D=3D 0 )
> +        BTree<K, V> bTreeCopy;
> +
> +        if ( readOnlyAction )
> +        {
> +            bTreeCopy =3D ( = BTree<K, V> )recordManager.fetch( recordId );
> +        }
> +        else
> +        {
> +            bTreeCopy =3D this;
> +        }
> +
> +        if ( bTreeCopy.rootId =3D=3D 0 )
>         {
>             return null;
>         }
>
> -        BPage<K, V> root =3D ( = BPage<K, V> ) recordManager.fetch( rootId, bpageSerializer );
> -        root.setRecordId( rootId );
> -        root.btree =3D this;
> +        BPage<K, V> root =3D ( = BPage<K, V> ) recordManager.fetch( bTreeCopy.rootId, = bpageSerializer );
> +        root.setRecordId( bTreeCopy.rootId = );
> +        root.btree =3D bTreeCopy;
>
>         return root;
>     }
> @@ -616,6 +770,115 @@ public class BTree<K, V> implements = Exte
>     }
>
>
> +    void setAsCurrentAction( ActionContext context )
> +    {
> +        if ( context !=3D null )
> +        {
> +            assert( isActionCapable = =3D=3D true );
> +            ( ( ActionRecordManager = )recordManager ).setCurrentActionContext( context );
> +        }
> +    }
> +
> +    void unsetAsCurrentAction( ActionContext context = )
> +    {
> +        if ( context !=3D null )
> +        {
> +            assert( isActionCapable = =3D=3D true );
> +            ( ( ActionRecordManager = )recordManager ).setCurrentActionContext( context );
> +        }
> +    }
> +
> +
> +    ActionContext beginAction( boolean readOnly )
> +    {
> +        ActionContext context =3D null;
> +        if ( isActionCapable )
> +        {
> +            context =3D ( ( = ActionRecordManager )recordManager ).beginAction( readOnly );
> +            this.setAsCurrentAction( = context );
> +        }
> +        return context;
> +    }
> +
> +
> +    void endAction( ActionContext context )
> +    {
> +        if ( context !=3D null )
> +        {
> +            assert( isActionCapable = );
> +            ( ( ActionRecordManager = )recordManager ).endAction( context );
> +           =  this.unsetAsCurrentAction( context );
> +        }
> +    }
> +
> +    void abortAction( ActionContext context )
> +    {
> +        if ( context !=3D 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 =3D = this.bpageSerializer.serialize( page );
> +        BPage<K,V> pageCopy =3D = this.bpageSerializer.deserialize( array );
> +        pageCopy.recordId =3D = page.recordId;
> +        pageCopy.btree =3D page.btree;
> +        return pageCopy;
> +    }
> +
> +    @SuppressWarnings("unchecked")
> +    private BTree<K,V> copyOnWrite() throws = IOException
> +    {
> +        ObjectOutputStream out =3D null;
> +        ObjectInputStream in =3D null;
> +        ByteArrayOutputStream bout =3D = null;
> +        ByteArrayInputStream bin =3D null;
> +
> +        BTree<K,V> tree;
> +
> +        try
> +        {
> +            bout =3D new = ByteArrayOutputStream();
> +            out =3D new = ObjectOutputStream( bout );
> +            out.writeObject( this = );
> +            out.flush();
> +            byte[]  arr =3D = bout.toByteArray();
> +            bin =3D new = ByteArrayInputStream( arr );
> +            in =3Dnew = ObjectInputStream( bin );
> +            tree =3D ( BTree<K, = V> )in.readObject();
> +        }
> +        catch ( ClassNotFoundException e )
> +        {
> +            throw new = WrappedRuntimeException( e );
> +        }
> +        finally
> +        {
> +            if ( bout !=3D null = )
> +               =  bout.close();
> +
> +            if ( out !=3D null )
> +               =  out.close();
> +
> +            if ( bin !=3D null )
> +               =  bin.close();
> +
> +            if ( in !=3D null )
> +               =  in.close();
> +        }
> +
> +        return tree;
> +    }
> +
> +
> +
>     public String toString()
>     {
>         StringBuilder sb =3D new = StringBuilder();
>
> Modified: = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/T= upleBrowser.java
> URL: http://svn.apache.org/viewvc/directory/apacheds/branches= /apacheds-jdbm/jdbm/src/main/java/jdbm/helper/TupleBrowser.java?rev=3D1161= 416&r1=3D1161415&r2=3D1161416&view=3Ddiff
> = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D
> --- = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/T= upleBrowser.java (original)
> +++ = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/helper/T= upleBrowser.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/B= aseRecordManager.java
> URL: http://svn.apache.org/viewvc/directory/apacheds/branches= /apacheds-jdbm/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java?rev=3D= 1161416&r1=3D1161415&r2=3D1161416&view=3Ddiff
> = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D
> --- = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/B= aseRecordManager.java (original)
> +++ = directory/apacheds/branches/apacheds-jdbm/jdbm/src/main/java/jdbm/recman/B= aseRecordManager.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 =3D new = ReentrantLock();
> +        private Condition cv =3D = 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 =3D true;
> +        }
> +
> +
> +        public void unsetWritten()
> +        {
> +            writer =3D 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 =3D new PageManager( recordFile = );
>         physMgr =3D new PhysicalRowIdManager( = pageMgr );
>         logMgr =3D new LogicalRowIdManager( = pageMgr );
> +        lockElements =3D 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 <=3D 0 )
> @@ -231,10 +333,20 @@ public final class BaseRecordManager
>             System.out.println( = "BaseRecordManager.delete() recid " + recid ) ;
>         }
>
> -        Location logRowId =3D new Location( = recid );
> -        Location physRowId =3D logMgr.fetch( = logRowId );
> -        physMgr.delete( physRowId );
> -        logMgr.delete( logRowId );
> +
> +        element =3D this.beginIO(recid, = IOType.WRITE_IO);
> +
> +        try
> +        {
> +               Location = logRowId =3D new Location( recid );
> +               Location = physRowId =3D 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 <=3D 0 )
>         {
>             throw new = IllegalArgumentException( I18n.err( I18n.ERR_536, recid ) );
>         }
>
> -        Location logRecid =3D new Location( = recid );
> -        Location physRecid =3D logMgr.fetch( = logRecid );
> -
> -        byte[] data =3D serializer.serialize( = obj );
> -
> -        if ( DEBUG )
> -        {
> -            System.out.println( = "BaseRecordManager.update() recid " + recid + " length " + data.length ) = ;
> -        }
> -
> -        Location newRecid =3D physMgr.update( = physRecid, data, 0, data.length );
> -
> -        if ( ! newRecid.equals( physRecid ) = )
> -        {
> -            logMgr.update( logRecid, = newRecid );
> -        }
> +        element =3D this.beginIO(recid, = IOType.WRITE_IO);
> +
> +        try
> +       {
> +               Location = logRecid =3D new Location( recid );
> +            Location physRecid =3D = logMgr.fetch( logRecid );
> +
> +            byte[] data =3D = serializer.serialize( obj );
> +
> +            if ( DEBUG )
> +            {
> +               =  System.out.println( "BaseRecordManager.update() recid " + recid + = " length " + data.length ) ;
> +            }
> +
> +            Location newRecid =3D = 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 <=3D 0 )
>         {
>             throw new = IllegalArgumentException( I18n.err( I18n.ERR_536, recid ) );
>         }
> -
> -        data =3D physMgr.fetch( logMgr.fetch( = new Location( recid ) ) );
> -
> -        if ( DEBUG )
> -        {
> -            System.out.println( = "BaseRecordManager.fetch() recid " + recid + " length " + data.length ) = ;
> -        }
> -        return serializer.deserialize( data = );
> +
> +       element =3D this.beginIO(recid, = IOType.READ_IO);
> +
> +       try
> +       {
> +               byte[] data;
> +
> +            data =3D physMgr.fetch( = logMgr.fetch( new Location( recid ) ) );
> +
> +            if ( DEBUG )
> +            {
> +               =  System.out.println( "BaseRecordManager.fetch() recid " + recid + " = length " + data.length ) ;
> +            }
> +            result =3D = 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 =3D false;
> +        LockElement element =3D null;
> +
> +        // loop until we successfully verify = that there is no concurrent writer
> +/*
> +        element =3D lockElements.get( recid = );
> +        do
> +        {
> +            if ( element =3D=3D null = )
> +            {
> +                element =3D = new LockElement();
> +
> +                if ( io =3D=3D= IOType.READ_IO )
> +                   =  element.bumpReaders();
> +                else
> +                   =  element.setWritten();
> +
> +               =  LockElement existingElement =3D lockElements.putIfAbsent( recid, = element );
> +
> +                if ( = existingElement =3D=3D null )
> +                   =  lockVerified =3D true;
> +                else
> +                   =  element =3D existingElement;
> +            }
> +            else
> +            {
> +                Lock lock = =3D 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 =3D=3D IOType.READ_IO )
> +                   =      element.bumpReaders();
> +                   =  else
> +                   =      element.setWritten();
> +                   =  lockVerified =3D true;
> +                }
> +                else
> +                {
> +                   =  if ( io =3D=3D IOType.READ_IO )
> +                   =      element.bumpReaders();
> +                   =  else
> +                   =      element.setWritten();
> +
> +                   =  LockElement existingElement =3D lockElements.get( recid );
> +
> +                   =  if ( element !=3D existingElement )
> +                   =      element =3D existingElement;
> +                   =  else
> +                   =      lockVerified =3D 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 =3D element.getLock();
> +        lock.lock();
> +
> +        if ( io =3D=3D 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 =3D=3D IOType.READ_IO )
> +            return = element.beingWritten();
> +        else
> +            return ( = element.anyReaders() || element.beingWritten() );
> +    }
> +
>  }
>
>
>



-- =
Regards,
Cordialement,
Emmanuel L=E9charny
www.iktek.com
=




= --Apple-Mail-5-962290853--