Return-Path: X-Original-To: apmail-directory-commits-archive@www.apache.org Delivered-To: apmail-directory-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4485891DF for ; Mon, 7 May 2012 07:53:53 +0000 (UTC) Received: (qmail 77647 invoked by uid 500); 7 May 2012 07:53:53 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 77127 invoked by uid 500); 7 May 2012 07:53:49 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 77101 invoked by uid 99); 7 May 2012 07:53:48 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 07 May 2012 07:53:48 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 07 May 2012 07:53:44 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 6B7952388962 for ; Mon, 7 May 2012 07:53:24 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1334904 [1/3] - in /directory/apacheds/branches/apacheds-txns: core-api/src/main/java/org/apache/directory/server/core/api/ core-api/src/main/java/org/apache/directory/server/core/api/interceptor/ core-api/src/main/java/org/apache/director... Date: Mon, 07 May 2012 07:53:22 -0000 To: commits@directory.apache.org From: saya@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120507075324.6B7952388962@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: saya Date: Mon May 7 07:53:21 2012 New Revision: 1334904 URL: http://svn.apache.org/viewvc?rev=1334904&view=rev Log: -Changes to handle logical data(or logical caches) - While a cursor is built or ReadWrite txn is in progress, the thread hold a shared lock. If it needs to change logical data derived from transactional data, it escalates its lock to exclusive lock. This escalation might throw TxnConflictException - Multiple locks to manage different caches is replaced with one single lock at the txn manager layer. - If a txn fails (conflict or any other exception) all logical caches are rebuilt from underlying transactionally managed data. Here many optimizations are possible. -Added TxnConflictIT to MigratedStockCoreISuite(more basic multithreaded tests would be good) This completes the forward going changes in the transactional layer. Tests are passing. This would be a good checkpoint. Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/DirectoryService.java directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/ReferralManager.java directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/BaseInterceptor.java directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/Interceptor.java directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/schema/SchemaPartition.java directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/txn/TxnManager.java directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockDirectoryService.java directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/schema/AbstractMetaSchemaObjectHandler.java directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/suites/MigratedStockCoreISuite.java directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/ReferralManagerImpl.java directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultOperationExecutionManager.java directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/AbstractTransaction.java directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadOnlyTxn.java directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadWriteTxn.java directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/Transaction.java directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/TxnManagerInternal.java directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java directory/apacheds/branches/apacheds-txns/interceptors/authz/src/main/java/org/apache/directory/server/core/authz/AciAuthorizationInterceptor.java directory/apacheds/branches/apacheds-txns/interceptors/authz/src/main/java/org/apache/directory/server/core/authz/GroupCache.java directory/apacheds/branches/apacheds-txns/interceptors/authz/src/main/java/org/apache/directory/server/core/authz/TupleCache.java directory/apacheds/branches/apacheds-txns/interceptors/exception/src/main/java/org/apache/directory/server/core/exception/ExceptionInterceptor.java directory/apacheds/branches/apacheds-txns/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java directory/apacheds/branches/apacheds-txns/interceptors/subtree/src/main/java/org/apache/directory/server/core/subtree/SubentryInterceptor.java Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/DirectoryService.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/DirectoryService.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/DirectoryService.java (original) +++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/DirectoryService.java Mon May 7 07:53:21 2012 @@ -603,7 +603,12 @@ public interface DirectoryService extend * @return The TriggerExecution AdministrativePoint cache */ DnNode getTriggerExecutionAPCache(); - + + + /** + * Reset all the caches to their initial state + */ + void resetCaches(); /** * @return true if the password policy is enabled, false otherwise Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/ReferralManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/ReferralManager.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/ReferralManager.java (original) +++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/ReferralManager.java Mon May 7 07:53:21 2012 @@ -111,6 +111,15 @@ public interface ReferralManager * @exception If the initialization failed */ void init( DirectoryService directoryService, String... suffixes ) throws Exception; + + /** Reinitalize the referrals + * + * Rereads the referalls + * + * @param directoryService The associated LDAP service + * @throws LdapException + */ + void reinitialize( DirectoryService directoryService ) throws LdapException; /** Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/BaseInterceptor.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/BaseInterceptor.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/BaseInterceptor.java (original) +++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/BaseInterceptor.java Mon May 7 07:53:21 2012 @@ -151,6 +151,15 @@ public abstract class BaseInterceptor im { // unused } + + + /** + * {@inheritDoc} + */ + public void reinitLogicalData( DirectoryService directoryService ) throws LdapException + { + // Do nothing by default + } /** @@ -375,6 +384,15 @@ public abstract class BaseInterceptor im public void destroy() { } + + + /** + * {@inheritDoc} + */ + public void reinitLogicalData( DirectoryService directoryService ) throws LdapException + { + // Do nothing by default + } /** Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/Interceptor.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/Interceptor.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/Interceptor.java (original) +++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/Interceptor.java Mon May 7 07:53:21 2012 @@ -124,6 +124,15 @@ public interface Interceptor * when this intercepter is unloaded from interceptor chain. */ void destroy(); + + + /** + * Reintializes the logical data from the data managed by txn layer + * + * @param directoryService + * @throws LdapException + */ + void reinitLogicalData( DirectoryService directoryService ) throws LdapException; /** Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java (original) +++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java Mon May 7 07:53:21 2012 @@ -124,9 +124,14 @@ public class ModifyOperationContext exte { super.saveOriginalContext(); - for ( Modification mod : getModItems() ) + List items = getModItems(); + + if ( items != null ) { - originalModItems.add( mod.clone() ); + for ( Modification mod : items ) + { + originalModItems.add( mod.clone() ); + } } } @@ -138,8 +143,13 @@ public class ModifyOperationContext exte { super.resetContext(); alteredEntry = null; - modItems.clear(); - modItems.addAll( originalModItems ); + + if ( modItems != null ) + { + modItems.clear(); + modItems.addAll( originalModItems ); + } + originalModItems.clear(); } Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/schema/SchemaPartition.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/schema/SchemaPartition.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/schema/SchemaPartition.java (original) +++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/schema/SchemaPartition.java Mon May 7 07:53:21 2012 @@ -263,6 +263,9 @@ public final class SchemaPartition exten */ public void add( AddOperationContext addContext ) throws LdapException { + // Ensure logical data in registries is consistent + addContext.getSession().getDirectoryService().getTxnManager().startLogicalDataChange(); + // At this point, the added SchemaObject does not exist in the partition // We have to check if it's enabled and then inject it into the registries // but only if it does not break the server. @@ -324,6 +327,9 @@ public final class SchemaPartition exten throw new LdapUnwillingToPerformException(); } + // Ensure logical data in registries is consistent + deleteContext.getSession().getDirectoryService().getTxnManager().startLogicalDataChange(); + // The SchemaObject always exist when we reach this method. synchronizer.delete( deleteContext, cascade ); @@ -367,6 +373,9 @@ public final class SchemaPartition exten boolean cascade = modifyContext.hasRequestControl( Cascade.OID ); + // Ensure logical data in registries is consistent + modifyContext.getSession().getDirectoryService().getTxnManager().startLogicalDataChange(); + synchronizer.modify( modifyContext, targetEntry, cascade ); if ( !modifyContext.getDn().equals( SCHEMA_MODIFICATION_DN ) ) @@ -386,6 +395,10 @@ public final class SchemaPartition exten CoreSession session = moveContext.getSession(); LookupOperationContext lookupContext = new LookupOperationContext( session, moveContext.getDn(), SchemaConstants.ALL_ATTRIBUTES_ARRAY ); Entry entry = session.getDirectoryService().getPartitionNexus().lookup( lookupContext ); + + // Ensure logical data in registries is consistent + session.getDirectoryService().getTxnManager().startLogicalDataChange(); + synchronizer.move( moveContext, entry, cascade ); updateSchemaModificationAttributes( moveContext ); } @@ -400,6 +413,10 @@ public final class SchemaPartition exten CoreSession session = moveAndRenameContext.getSession(); LookupOperationContext lookupContext = new LookupOperationContext( session, moveAndRenameContext.getDn(), SchemaConstants.ALL_ATTRIBUTES_ARRAY ); Entry entry = session.getDirectoryService().getPartitionNexus().lookup( lookupContext ); + + // Ensure logical data in registries is consistent + session.getDirectoryService().getTxnManager().startLogicalDataChange(); + synchronizer.moveAndRename( moveAndRenameContext, entry, cascade ); updateSchemaModificationAttributes( moveAndRenameContext ); } @@ -412,6 +429,9 @@ public final class SchemaPartition exten { boolean cascade = renameContext.hasRequestControl( Cascade.OID ); + // Ensure logical data in registries is consistent + renameContext.getSession().getDirectoryService().getTxnManager().startLogicalDataChange(); + // First update the registries synchronizer.rename( renameContext, cascade ); Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/txn/TxnManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/txn/TxnManager.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/txn/TxnManager.java (original) +++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/txn/TxnManager.java Mon May 7 07:53:21 2012 @@ -19,6 +19,8 @@ */ package org.apache.directory.server.core.api.txn; +import org.apache.directory.shared.ldap.model.exception.LdapException; + /** * The transaction manager interface. @@ -103,4 +105,31 @@ public interface TxnManager * Flushes the committed txns to partitions. */ void applyPendingTxns(); + + + /** + * Called when data derived from the underlying + * data managed by the txn manager is about to be + * changed. Ensures Every txn sees a consistent + * version of the data. + * + * @throws LdapException with a root cause as TxnConflictException + */ + void startLogicalDataChange() throws LdapException; + + + /** + * Called when txn manager wont need data derived from + * data managed by the txn layer is not needed any more. + */ + void endLogicalDataRead(); + + + /** + * Prepares the current txn for logical data reinit + * + * @return TRUE if txn needs to do logical data reinit + */ + boolean prepareForLogicalDataReinit(); + } Modified: directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockDirectoryService.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockDirectoryService.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockDirectoryService.java (original) +++ directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockDirectoryService.java Mon May 7 07:53:21 2012 @@ -77,6 +77,13 @@ public class MockDirectoryService implem { this.count = count; } + + + public void resetCaches() + { + // do nothing + } + public Hashtable getEnvironment() { Modified: directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/schema/AbstractMetaSchemaObjectHandler.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/schema/AbstractMetaSchemaObjectHandler.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/schema/AbstractMetaSchemaObjectHandler.java (original) +++ directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/schema/AbstractMetaSchemaObjectHandler.java Mon May 7 07:53:21 2012 @@ -77,6 +77,9 @@ public abstract class AbstractMetaSchema */ protected boolean isOnDisk( Dn dn ) { + + getService().getTxnManager().applyPendingTxns(); + // do not change the value of getSchemaPath to lowercase // on Linux this gives a wrong path String schemaObjectFileName = getSchemaPath( dn ); Modified: directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/suites/MigratedStockCoreISuite.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/suites/MigratedStockCoreISuite.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/suites/MigratedStockCoreISuite.java (original) +++ directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/suites/MigratedStockCoreISuite.java Mon May 7 07:53:21 2012 @@ -35,6 +35,7 @@ import org.apache.directory.server.core. import org.apache.directory.server.core.authz.MoveRenameAuthorizationIT; import org.apache.directory.server.core.authz.SearchAuthorizationIT; import org.apache.directory.server.core.exception.ExceptionServiceIT; +import org.apache.directory.server.core.txn.TxnConflictIT; import org.apache.directory.server.core.integ.FrameworkSuite; import org.apache.directory.server.core.operations.add.PasswordHashingInterceptorTest; import org.junit.runner.RunWith; @@ -70,7 +71,10 @@ import org.junit.runners.Suite; SearchAuthorizationIT.class, // exception - ExceptionServiceIT.class + ExceptionServiceIT.class, + + // Txn Conflict/Serialization + TxnConflictIT.class } ) public class MigratedStockCoreISuite Modified: directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java (original) +++ directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java Mon May 7 07:53:21 2012 @@ -32,7 +32,7 @@ import org.apache.directory.shared.ldap. @RunWith ( FrameworkRunner.class ) -@CreateDS(name = "TxnConflictIT") +@CreateDS(enableChangeLog = false, name = "TxnConflictIT") @ApplyLdifs( { "dn: cn=test1, ou=system", @@ -242,13 +242,23 @@ public class TxnConflictIT extends Abstr connection.add( entry ); } + private void doModifyConfclictingWithDelete() throws Exception + { + LdapContext sysRoot = getSystemContext( getService() ); + + // The added value + Attributes attrs = new BasicAttributes( "telephoneNumber", "1 650 300 6070", true ); + + // Add the Ava + sysRoot.modifyAttributes( "cn=test3,ou=users", DirContext.ADD_ATTRIBUTE, attrs ); + } private void doModifyConfclictingWithRename() throws Exception { LdapContext sysRoot = getSystemContext( getService() ); // The added value - Attributes attrs = new BasicAttributes( "telephoneNumber", "1 650 300 6088", true ); + Attributes attrs = new BasicAttributes( "telephoneNumber", "1 650 300 6071", true ); // Add the Ava sysRoot.modifyAttributes( "cn=test3,ou=users", DirContext.ADD_ATTRIBUTE, attrs ); @@ -267,7 +277,7 @@ public class TxnConflictIT extends Abstr { try { - doConflictingModify(); + doModifyConfclictingWithDelete(); } catch ( NameNotFoundException e ) { Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/ReferralManagerImpl.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/ReferralManagerImpl.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/ReferralManagerImpl.java (original) +++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/ReferralManagerImpl.java Mon May 7 07:53:21 2012 @@ -73,8 +73,6 @@ public class ReferralManagerImpl impleme */ public ReferralManagerImpl( DirectoryService directoryService ) throws LdapException { - lockWrite(); - referrals = new DnNode(); PartitionNexus nexus = directoryService.getPartitionNexus(); @@ -83,8 +81,18 @@ public class ReferralManagerImpl impleme init( directoryService, suffixes.toArray( new String[] {} ) ); - - unlock(); + } + + + public void reinitialize( DirectoryService directoryService ) throws LdapException + { + referrals = new DnNode(); + + PartitionNexus nexus = directoryService.getPartitionNexus(); + Set suffixes = nexus.listSuffixes(); + + init( directoryService, suffixes.toArray( new String[] + {} ) ); } @@ -181,14 +189,8 @@ public class ReferralManagerImpl impleme { Entry entry = cursor.get(); - // Lock the referralManager - lockWrite(); - // Add it at the right place addReferral( entry ); - - // Unlock the referralManager - unlock(); } cursor.close(); Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultOperationExecutionManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultOperationExecutionManager.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultOperationExecutionManager.java (original) +++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultOperationExecutionManager.java Mon May 7 07:53:21 2012 @@ -277,7 +277,7 @@ public class DefaultOperationExecutionMa // log the change txnLogManager.log( changeContainer, false ); - //TODO TODO TODO REMOVE THIS + // Mostly for schema partition partition.add( addContext ); } catch ( LdapException le ) @@ -301,7 +301,7 @@ public class DefaultOperationExecutionMa { Dn dn = deleteContext.getDn(); - //TODO TODO TODO REMOVE THIS + // Mostly for schema partition partition.delete( deleteContext ); // Add write dependency on the dn @@ -498,7 +498,7 @@ public class DefaultOperationExecutionMa {} ) ); modifyContext.setAlteredEntry( modifiedEntry ); - //TODO TODO TODO REMOVE THIS + // Mostly for schema partition partition.modify( modifyContext ); } @@ -1022,7 +1022,7 @@ public class DefaultOperationExecutionMa rename( partition, oldDn, newRdn, deleteOldRdn, null, originalEntry ); } - //TODO TODO TODO REMOVE THIS + // Mostly for schema partition partition.rename( renameContext ); } catch ( Exception e ) @@ -1346,7 +1346,7 @@ public class DefaultOperationExecutionMa move( partition, oldDn, newSuperior, newDn, modifiedEntry, originalEntry ); - //TODO TODO TODO REMOVE THIS + // Mostly for schema partition partition.move( moveContext ); } Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/AbstractTransaction.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/AbstractTransaction.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/AbstractTransaction.java (original) +++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/AbstractTransaction.java Mon May 7 07:53:21 2012 @@ -51,26 +51,43 @@ abstract class AbstractTransaction imple /** List of txns that this txn depends on */ private List txnsToCheck = new ArrayList(); - /** The number of operations using this transaction */ - private int nbRef; - protected long id; private static AtomicLong counter = new AtomicLong( 0 ); - /** Trus if this is the only running txn */ - private boolean isExclusive = false; - + /** True optimistic lock is held by the txn */ + private boolean isOptimisticLockHeld = false; + + /** version of the logical data vseen by this txn */ + private long myLogicalDataVersion; - public boolean isExclusive() + public boolean isOptimisticLockHeld() + { + return isOptimisticLockHeld; + } + + + public void setOptimisticLockHeld() + { + isOptimisticLockHeld = true; + } + + + public void clearOptimisticLockHeld() { - return isExclusive; + isOptimisticLockHeld = false; } - public void setExclusive() + public long getLogicalDataVersion() { - isExclusive = true; + return myLogicalDataVersion; + } + + + public void setLogicalDataVersion( long logicalDataVersion ) + { + myLogicalDataVersion = logicalDataVersion; } @@ -80,7 +97,6 @@ abstract class AbstractTransaction imple public AbstractTransaction() { txnState = State.INITIAL; - nbRef = 0; id = counter.getAndIncrement(); } @@ -88,20 +104,12 @@ abstract class AbstractTransaction imple /** * {@inheritDoc} */ - protected void startTxn( long startTime ) + public void startTxn( long startTime, long logicalDataVerion ) { this.startTime = startTime; txnState = State.READ; - nbRef++; } - - public void reuseTxn() - { - nbRef++; - } - - /** * {@inheritDoc} */ @@ -117,12 +125,7 @@ abstract class AbstractTransaction imple public void commitTxn( long commitTime ) { this.commitTime = commitTime; - nbRef--; - - if ( nbRef == 0 ) - { - txnState = State.COMMIT; - } + txnState = State.COMMIT; } Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java (original) +++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java Mon May 7 07:53:21 2012 @@ -43,6 +43,7 @@ import org.apache.directory.server.core. import org.apache.directory.server.core.api.txn.TxnLogManager; import org.apache.directory.server.core.api.txn.logedit.LogEdit; import org.apache.directory.server.core.shared.txn.logedit.TxnStateChange; +import org.apache.directory.shared.ldap.model.exception.LdapException; /** @@ -65,7 +66,7 @@ class DefaultTxnManager implements TxnMa private Lock writeTxnsLock = new ReentrantLock(); /** Used to order txns in case of conflicts */ - private ReadWriteLock optimisticLock = new ReentrantReadWriteLock(); + private ReentrantReadWriteLock optimisticLock = new ReentrantReadWriteLock(); /** Latest committed txn on which read only txns can depend */ private AtomicReference latestCommittedTxn = new AtomicReference(); @@ -105,6 +106,9 @@ class DefaultTxnManager implements TxnMa private AtomicInteger pending = new AtomicInteger(); + /** Logical data version number */ + private long logicalDataVersion = 0; + /** Per thread txn context */ static final ThreadLocal txnVar = new ThreadLocal() @@ -178,6 +182,24 @@ class DefaultTxnManager implements TxnMa /** * {@inheritDoc} */ + public long getLogicalDataVersion() + { + return logicalDataVersion; + } + + + /** + * {@inheritDoc} + */ + public void bumpLogicalDataVersion() + { + logicalDataVersion++; + } + + + /** + * {@inheritDoc} + */ public TxnHandle retryTransaction() throws Exception { Transaction curTxn = getCurTxn(); @@ -193,7 +215,6 @@ class DefaultTxnManager implements TxnMa // abort current txn and start a new read write txn - abortReadWriteTxn( ( ReadWriteTxn ) curTxn ); curTxn.abortTxn(); return beginReadWriteTxn( true ); @@ -239,17 +260,15 @@ class DefaultTxnManager implements TxnMa throw new IllegalStateException( " trying to commit non existent txn " ); } - boolean isExclusive = txn.isExclusive(); - try - { + { if ( flushFailed ) { throw new IOException( "Flushing of txns failed" ); } - + prepareForEndingTxn( txn ); - + if ( txn instanceof ReadOnlyTxn ) { txn.commitTxn( txn.getStartTime() ); @@ -261,14 +280,8 @@ class DefaultTxnManager implements TxnMa } finally { - if ( !isExclusive ) - { - optimisticLock.readLock().unlock(); - } - else - { - optimisticLock.writeLock().unlock(); - } + // Release optimistic lock if it is held + releaseOptimisticLock(); } setCurTxn( null ); @@ -289,8 +302,6 @@ class DefaultTxnManager implements TxnMa throw new IllegalStateException( "Trying to abort while there is not txn " ); } - boolean isExclusive = txn.isExclusive(); - try { prepareForEndingTxn( txn ); @@ -301,18 +312,12 @@ class DefaultTxnManager implements TxnMa } txn.abortTxn(); - setCurTxn( null ); } finally { - if ( !isExclusive ) - { - optimisticLock.readLock().unlock(); - } - else - { - optimisticLock.writeLock().unlock(); - } + // Release optimistic lock if it is held + releaseOptimisticLock(); + setCurTxn( null ); } //System.out.println( "TRAN: Aborted " + txn ); @@ -402,6 +407,127 @@ class DefaultTxnManager implements TxnMa /** + * {@inheritDoc} + */ + public void startLogicalDataChange() throws LdapException + { + Transaction curTxn = getCurTxn(); + + if (curTxn == null) + { + return; + } + // Should have a rw txn + if ( !( curTxn instanceof ReadWriteTxn ) ) + { + // Cannot start a TXN when a RW txn is ongoing + throw new IllegalStateException( "Unexpected txn state when starting logical data change txn: " + + curTxn ); + } + + // If txn is already exclusive then it can start logical data change immediately + + if ( !curTxn.isOptimisticLockHeld() ) + { + throw new IllegalStateException( "Unexpected txn state when starting logical data change txn: " + + " txn is not holding optimistic lock:"+ + curTxn ); + } + + // If lock is already held exclusively by the txn, then return + if ( optimisticLock.isWriteLockedByCurrentThread() ) + { + return; + } + + long txnLogicalDataVersion = curTxn.getLogicalDataVersion(); + + // Get operations lock in exclusive mode + optimisticLock.readLock().unlock(); + optimisticLock.writeLock().lock(); + + // If somebody raced and changed logical data, then bail out + if ( getLogicalDataVersion() != txnLogicalDataVersion ) + { + + TxnConflictException e = new TxnConflictException(); + throw new LdapException(e); + } + + // Finally bump of logical data version number + bumpLogicalDataVersion(); + } + + + /** + * {@inheritDoc} + */ + public void endLogicalDataRead() + { + // Should only be called for read only txns + Transaction curTxn = getCurTxn(); + + if (curTxn == null || !( curTxn instanceof ReadOnlyTxn )) + { + throw new IllegalStateException( "Unexpected txn state when ending logical data read:" + curTxn ); + } + + if ( !curTxn.isOptimisticLockHeld() ) + { + throw new IllegalStateException( "Unexpected txn state when ending logical data read, optimistic lock not held:" + + curTxn ); + } + + releaseOptimisticLock(); + } + + + /** + * {@inheritDoc} + */ + public boolean prepareForLogicalDataReinit() + { + Transaction curTxn = getCurTxn(); + + if (curTxn == null || !( curTxn instanceof ReadWriteTxn )) + { + throw new IllegalStateException( "Unexpected txn state when preparing for logical data reinit:" + curTxn ); + } + + if ( optimisticLock.isWriteLockedByCurrentThread() ) + { + return true; + } + else + { + return false; + } + } + + + /** + * If the thread holds optimistic lock, release it + */ + private void releaseOptimisticLock() + { + Transaction curTxn = getCurTxn(); + + if ( curTxn.isOptimisticLockHeld() ) + { + if ( optimisticLock.isWriteLockedByCurrentThread() ) + { + optimisticLock.writeLock().unlock(); + } + else + { + optimisticLock.readLock().unlock(); + } + + curTxn.clearOptimisticLockHeld(); + } + } + + /** * Begins a read only txn. A read only txn does not put any log edits * to the txn log.Its start time is the latest committed txn's commit time. */ @@ -410,7 +536,9 @@ class DefaultTxnManager implements TxnMa ReadOnlyTxn txn = new ReadOnlyTxn(); ReadWriteTxn lastTxnToCheck = null; - optimisticLock.readLock().lock(); + optimisticLock.readLock().lock(); + txn.setOptimisticLockHeld(); + txn.setLogicalDataVersion( logicalDataVersion ); /* * Set the start time as the latest committed txn's commit time. We need to make sure that @@ -436,7 +564,7 @@ class DefaultTxnManager implements TxnMa long startTime; startTime = lastTxnToCheck.getCommitTime(); - txn.startTxn( startTime ); + txn.startTxn( startTime, logicalDataVersion ); buildCheckList( txn, lastTxnToCheck ); @@ -471,8 +599,10 @@ class DefaultTxnManager implements TxnMa else { optimisticLock.writeLock().lock(); - txn.setExclusive(); } + + txn.setOptimisticLockHeld(); + txn.setLogicalDataVersion( logicalDataVersion ); /* * Get the start time and last txn to depend on @@ -485,7 +615,7 @@ class DefaultTxnManager implements TxnMa try { txnLogManager.log( logRecord, false ); - txn.startTxn( logRecord.getLogAnchor().getLogLSN() ); + txn.startTxn( logRecord.getLogAnchor().getLogLSN(), logicalDataVersion ); do { @@ -502,14 +632,10 @@ class DefaultTxnManager implements TxnMa } catch ( Exception e ) { - if ( txn.isExclusive() == false ) - { - optimisticLock.readLock().unlock(); - } - else - { - optimisticLock.writeLock().unlock(); - } + // Release optimistic lock if held + setCurTxn(txn); + releaseOptimisticLock(); + } finally { @@ -604,7 +730,7 @@ class DefaultTxnManager implements TxnMa throw new IllegalStateException( " prepareForEndingTxn: txn has unpexptected start time " + txn + " expected: " + lastTxnToCheck ); } - + if ( lastTxnToCheck.getRefCount().get() <= 0 ) { throw new IllegalStateException( " prepareForEndingTxn: lastTxnToCheck has unexpected ref cnt " + Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadOnlyTxn.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadOnlyTxn.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadOnlyTxn.java (original) +++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadOnlyTxn.java Mon May 7 07:53:21 2012 @@ -27,23 +27,5 @@ package org.apache.directory.server.core /** Package protected */ class ReadOnlyTxn extends AbstractTransaction { - private int nbRef = 0; - - - public void releaseTxn() - { - nbRef--; - } - - - public void acquireTxn() - { - nbRef++; - } - - - public boolean isReused() - { - return nbRef > 1; - } + } Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadWriteTxn.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadWriteTxn.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadWriteTxn.java (original) +++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/ReadWriteTxn.java Mon May 7 07:53:21 2012 @@ -670,6 +670,22 @@ class ReadWriteTxn extends AbstractTrans } } } + + + public void clearLogEdits() + { + LogEdit txnStartMarker = logEdits.get( 0 ); + + logEdits.clear(); + logEdits.add( txnStartMarker ); + + forwardIndexAdds.clear(); + reverseIndexAdds.clear(); + indexDeletes.clear(); + + readDns.clear(); + writeDns.clear(); + } /** Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/Transaction.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/Transaction.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/Transaction.java (original) +++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/Transaction.java Mon May 7 07:53:21 2012 @@ -37,10 +37,34 @@ import org.apache.directory.shared.ldap. /** Package protected */ interface Transaction extends TxnHandle { - boolean isExclusive(); + /** + * returns TRUE if optimisticLock held, false otherwise + * + * @return TRUE if optimisticLock held, false otherwise + */ + boolean isOptimisticLockHeld(); + + + /** + * Called after txn gets the optimistic lock + * + */ + void setOptimisticLockHeld(); - void setExclusive(); + /** + * Called after txn release the optimistic lock + */ + void clearOptimisticLockHeld(); + + + /** + * + * Returns the version of the logical data this txn sees. + * + * @return version of the logical data this txn sees. + */ + long getLogicalDataVersion(); /** @@ -65,10 +89,9 @@ interface Transaction extends TxnHandle * is updated accordingly. * * @param startTime start time of the txn + * @param version of the logical data this txn sees */ - //void startTxn( long startTime ); - - void reuseTxn(); + void startTxn( long startTime, long logicalDataVerion ); /** Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/TxnManagerInternal.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/TxnManagerInternal.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/TxnManagerInternal.java (original) +++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/TxnManagerInternal.java Mon May 7 07:53:21 2012 @@ -37,4 +37,19 @@ interface TxnManagerInternal extends Txn * @return current txn */ Transaction getCurTxn(); + + + /** + * Returns the current version of logical data + * + * @return the current version of logical data + */ + long getLogicalDataVersion(); + + + /** + * Bumps the current version of logical data. Caller is + * assumed to provide synchronization. + */ + void bumpLogicalDataVersion(); } Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java?rev=1334904&r1=1334903&r2=1334904&view=diff ============================================================================== --- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java (original) +++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java Mon May 7 07:53:21 2012 @@ -300,7 +300,7 @@ public class DefaultDirectoryService imp private DnFactory dnFactory; /** The Subentry cache */ - SubentryCache subentryCache = new SubentryCache(); + SubentryCache subentryCache; /** The Subtree evaluator instance */ private SubtreeEvaluator evaluator; @@ -1263,7 +1263,8 @@ public class DefaultDirectoryService imp } catch ( LdapException e ) { - //e.printStackTrace(); + e.printStackTrace(); + throw e; } catch ( Exception e ) { @@ -1901,6 +1902,19 @@ public class DefaultDirectoryService imp } } + + private void initializeCaches() + { + // Initialize the AP caches + accessControlAPCache = new DnNode(); + collectiveAttributeAPCache = new DnNode(); + subschemaAPCache = new DnNode(); + triggerExecutionAPCache = new DnNode(); + + // Reinit the subentry cache as well + subentryCache = new SubentryCache(); + } + /** * Kicks off the initialization of the entire system. @@ -1919,15 +1933,12 @@ public class DefaultDirectoryService imp { setDefaultInterceptorConfigurations(); } - + cacheService = new CacheService(); cacheService.initialize( this ); - // Initialize the AP caches - accessControlAPCache = new DnNode(); - collectiveAttributeAPCache = new DnNode(); - subschemaAPCache = new DnNode(); - triggerExecutionAPCache = new DnNode(); + // prepare caches + initializeCaches(); dnFactory = new DefaultDnFactory( schemaManager, cacheService.getCache( "dnCache" ) ); @@ -2390,6 +2401,14 @@ public class DefaultDirectoryService imp return triggerExecutionAPCache; } + + /** + * {@inheritDoc} + */ + public void resetCaches() + { + initializeCaches(); + } /** * {@inheritDoc}