directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject [directory-server] 02/02: Added the beginTransaction support in the server
Date Wed, 05 Sep 2018 21:45:24 GMT
This is an automated email from the ASF dual-hosted git repository.

elecharny pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/directory-server.git

commit 86929a01f7bf0d4ca678a1164e9bbdcd21c8c32d
Author: Emmanuel L├ęcharny <elecharny@symas.com>
AuthorDate: Wed Sep 5 23:45:19 2018 +0200

    Added the beginTransaction support in the server
---
 .../directory/server/core/api/CoreSession.java     |  43 ++++++
 .../server/core/api/LdapCoreSessionConnection.java |   9 ++
 .../directory/server/core/api/MockCoreSession.java |  52 ++++++++
 .../server/core/api/MockOperationManager.java      |   2 +
 .../server/core/shared/DefaultCoreSession.java     |  68 ++++++++++
 .../server/core/DefaultOperationManager.java       | 148 +++++++++++++++++----
 .../handlers/extended/StartTransactionHandler.java |  98 ++++++++++++++
 7 files changed, 392 insertions(+), 28 deletions(-)

diff --git a/core-api/src/main/java/org/apache/directory/server/core/api/CoreSession.java
b/core-api/src/main/java/org/apache/directory/server/core/api/CoreSession.java
index e9bc149..942f8aa 100644
--- a/core-api/src/main/java/org/apache/directory/server/core/api/CoreSession.java
+++ b/core-api/src/main/java/org/apache/directory/server/core/api/CoreSession.java
@@ -20,6 +20,7 @@
 package org.apache.directory.server.core.api;
 
 
+import java.io.IOException;
 import java.net.SocketAddress;
 import java.util.List;
 import java.util.Set;
@@ -45,6 +46,8 @@ import org.apache.directory.api.ldap.model.name.Rdn;
 import org.apache.directory.server.constants.ServerDNConstants;
 import org.apache.directory.server.core.api.changelog.LogChange;
 import org.apache.directory.server.core.api.interceptor.context.OperationContext;
+import org.apache.directory.server.core.api.partition.Partition;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
 
 
 /**
@@ -821,4 +824,44 @@ public interface CoreSession
      * @param pwdMustChange If the password must change or not
      */
     void setPwdMustChange( boolean pwdMustChange );
+    
+    
+    /**
+     * @return <tt>true</tt> if a session transaction has been started
+     */
+    boolean hasSessionTransaction();
+    
+    
+    /**
+     * Set the flag indicating we have received the startTransaction extended operation
+     */
+    void beginSessionTransaction();
+    
+    
+    /**
+     * Set the flag indicating we have received the sendTransaction extended operation
+     * 
+     * @throws IOException If one of the transaction cannot be closed
+     */
+    void endSessionTransaction() throws IOException;
+    
+    
+    /**
+     * Retrieve a transaction associated with a partition, if we have one.
+     * 
+     * @return The found transaction, or null if no transaction  has been started
+     * @param partition
+     * @return
+     */
+    PartitionTxn getTransaction( Partition partition );
+    
+    
+    /**
+     * Add a transaction associated with a partition if it's not already stored in teh 
+     * transaction map.
+     * 
+     * @param partition The Partition which will be associated with the transaction
+     * @param transaction The transaction to set
+     */
+    void addTransaction( Partition partition, PartitionTxn transaction );
 }
diff --git a/core-api/src/main/java/org/apache/directory/server/core/api/LdapCoreSessionConnection.java
b/core-api/src/main/java/org/apache/directory/server/core/api/LdapCoreSessionConnection.java
index 1ce3cb7..99dbca2 100644
--- a/core-api/src/main/java/org/apache/directory/server/core/api/LdapCoreSessionConnection.java
+++ b/core-api/src/main/java/org/apache/directory/server/core/api/LdapCoreSessionConnection.java
@@ -1395,4 +1395,13 @@ public class LdapCoreSessionConnection extends AbstractLdapConnection
     {
         this.schemaManager = schemaManager;
     }
+    
+    
+    /**
+     * @return The session, if we have some
+     */
+    public CoreSession getSession()
+    {
+        return session;
+    }
 }
diff --git a/core-api/src/test/java/org/apache/directory/server/core/api/MockCoreSession.java
b/core-api/src/test/java/org/apache/directory/server/core/api/MockCoreSession.java
index 35c207b..4d7c86e 100644
--- a/core-api/src/test/java/org/apache/directory/server/core/api/MockCoreSession.java
+++ b/core-api/src/test/java/org/apache/directory/server/core/api/MockCoreSession.java
@@ -73,6 +73,8 @@ import org.apache.directory.server.core.api.interceptor.context.OperationContext
 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext;
+import org.apache.directory.server.core.api.partition.Partition;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
 import org.apache.directory.server.i18n.I18n;
 
 
@@ -984,4 +986,54 @@ public class MockCoreSession implements CoreSession
         this.pwdMustChange = pwdMustChange;
     }
 
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasSessionTransaction()
+    {
+        return false;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void beginSessionTransaction()
+    {
+        // Nothing to do
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void endSessionTransaction()
+    {
+        // Nothing to do
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public PartitionTxn getTransaction( Partition partition ) 
+    {
+        // We don't manage transactions in the MockOperationManager
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addTransaction( Partition partition, PartitionTxn transaction )
+    {
+        // Nothing to do
+    }
 }
diff --git a/core-api/src/test/java/org/apache/directory/server/core/api/MockOperationManager.java
b/core-api/src/test/java/org/apache/directory/server/core/api/MockOperationManager.java
index 13298fe..19dd0c8 100644
--- a/core-api/src/test/java/org/apache/directory/server/core/api/MockOperationManager.java
+++ b/core-api/src/test/java/org/apache/directory/server/core/api/MockOperationManager.java
@@ -40,6 +40,8 @@ import org.apache.directory.server.core.api.interceptor.context.MoveOperationCon
 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext;
+import org.apache.directory.server.core.api.partition.Partition;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
 
 
 public class MockOperationManager implements OperationManager
diff --git a/core-shared/src/main/java/org/apache/directory/server/core/shared/DefaultCoreSession.java
b/core-shared/src/main/java/org/apache/directory/server/core/shared/DefaultCoreSession.java
index bfceb2a..3a150bf 100644
--- a/core-shared/src/main/java/org/apache/directory/server/core/shared/DefaultCoreSession.java
+++ b/core-shared/src/main/java/org/apache/directory/server/core/shared/DefaultCoreSession.java
@@ -26,7 +26,9 @@ import java.net.SocketAddress;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import jdbm.recman.BaseRecordManager;
@@ -89,6 +91,8 @@ import org.apache.directory.server.core.api.interceptor.context.OperationContext
 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext;
+import org.apache.directory.server.core.api.partition.Partition;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
 import org.apache.directory.server.i18n.I18n;
 import org.apache.mina.core.session.IoSession;
 import org.slf4j.Logger;
@@ -129,6 +133,12 @@ public class DefaultCoreSession implements CoreSession
     /** flag to indicate if the password must be changed */
     private boolean pwdMustChange;
 
+    /** A flag set when the startTransaction extended operation has been received */
+    private boolean hasSessionTransaction;
+    
+    /** The Map containing the transactions associated with each partition */
+    private Map<String, PartitionTxn> transactionMap = new HashMap<>();
+
     /**
      * Creates a new instance of a DefaultCoreSession
      * @param principal The principal to use to process operation for this session
@@ -1458,4 +1468,62 @@ public class DefaultCoreSession implements CoreSession
     {
         this.pwdMustChange = pwdMustChange;
     }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasSessionTransaction()
+    {
+        return hasSessionTransaction;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void beginSessionTransaction()
+    {
+        hasSessionTransaction = true;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void endSessionTransaction() throws IOException
+    {
+        for ( Map.Entry<String, PartitionTxn> partitionTxn : transactionMap.entrySet()
)
+        {
+            partitionTxn.getValue().commit();
+        }
+        
+        hasSessionTransaction = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public PartitionTxn getTransaction( Partition partition ) 
+    {
+        return transactionMap.get( partition.getId() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addTransaction( Partition partition, PartitionTxn transaction )
+    {
+        if ( !transactionMap.containsKey( partition.getId() ) )
+        {
+            transactionMap.put( partition.getId(), transaction );
+        }
+    }
 }
diff --git a/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
b/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
index 0b560b6..18a94bd 100644
--- a/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
+++ b/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
@@ -99,7 +99,6 @@ public class DefaultOperationManager implements OperationManager
     /** A lock used to protect against concurrent operations */
     private ReadWriteLock rwLock = new ReentrantReadWriteLock( true );
 
-
     public DefaultOperationManager( DirectoryService directoryService )
     {
         this.directoryService = directoryService;
@@ -402,15 +401,28 @@ public class DefaultOperationManager implements OperationManager
         lockWrite();
 
         // Start a Write transaction right away
-        PartitionTxn transaction = null; 
+        PartitionTxn transaction = addContext.getSession().getTransaction( partition ); 
         
         try
         {
-            transaction = partition.beginWriteTransaction();
+            if ( transaction == null )
+            {
+                transaction = partition.beginWriteTransaction();
+                
+                if ( addContext.getSession().hasSessionTransaction() )
+                {
+                    addContext.getSession().addTransaction( partition, transaction );
+                }
+            }
+            
             addContext.setTransaction( transaction );
 
             head.add( addContext );
-            transaction.commit();
+            
+            if ( !addContext.getSession().hasSessionTransaction() )
+            {
+                transaction.commit();
+            }
         }
         catch ( LdapException le )
         {
@@ -720,11 +732,20 @@ public class DefaultOperationManager implements OperationManager
         lockWrite();
 
         // Start a Write transaction right away
-        PartitionTxn transaction = null; 
+        PartitionTxn transaction = deleteContext.getSession().getTransaction( partition );

         
         try
         {
-            transaction = partition.beginWriteTransaction();
+            if ( transaction == null )
+            {
+                transaction = partition.beginWriteTransaction();
+                
+                if ( deleteContext.getSession().hasSessionTransaction() )
+                {
+                    deleteContext.getSession().addTransaction( partition, transaction );
+                }
+            }
+            
             deleteContext.setTransaction( transaction );
 
             eagerlyPopulateFields( deleteContext );
@@ -734,7 +755,10 @@ public class DefaultOperationManager implements OperationManager
 
             head.delete( deleteContext );
 
-            transaction.commit();
+            if ( !deleteContext.getSession().hasSessionTransaction() )
+            {
+                transaction.commit();
+            }
         }
         catch ( LdapException le )
         {
@@ -1064,14 +1088,25 @@ public class DefaultOperationManager implements OperationManager
         
         Partition partition = directoryService.getPartitionNexus().getPartition( dn );
         modifyContext.setPartition( partition );
-        PartitionTxn partitionTxn = null;
         
         lockWrite();
+        
+        // Start a Write transaction right away
+        PartitionTxn transaction = modifyContext.getSession().getTransaction( partition );

 
         try
         {
-            partitionTxn = partition.beginWriteTransaction();
-            modifyContext.setTransaction( partitionTxn );
+            if ( transaction == null )
+            {
+                transaction = partition.beginWriteTransaction();
+                
+                if ( modifyContext.getSession().hasSessionTransaction() )
+                {
+                    modifyContext.getSession().addTransaction( partition, transaction );
+                }
+            }
+
+            modifyContext.setTransaction( transaction );
 
             // populate the context with the old entry
             eagerlyPopulateFields( modifyContext );
@@ -1080,15 +1115,19 @@ public class DefaultOperationManager implements OperationManager
             Interceptor head = directoryService.getInterceptor( modifyContext.getNextInterceptor()
);
 
             head.modify( modifyContext );
-            partitionTxn.commit();
+            
+            if ( !modifyContext.getSession().hasSessionTransaction() )
+            {
+                transaction.commit();
+            }
         }
         catch ( LdapException le )
         {
             try 
             {
-                if ( partitionTxn != null )
+                if ( transaction != null )
                 {
-                    partitionTxn.abort();
+                    transaction.abort();
                 }
                 
                 throw le;
@@ -1102,7 +1141,7 @@ public class DefaultOperationManager implements OperationManager
         {
             try 
             {
-                partitionTxn.abort();
+                transaction.abort();
                 
                 throw new LdapOtherException( ioe.getMessage(), ioe );
             }
@@ -1228,11 +1267,20 @@ public class DefaultOperationManager implements OperationManager
         moveContext.setPartition( partition );
 
         // Start a Write transaction right away
-        PartitionTxn transaction = null; 
+        PartitionTxn transaction = moveContext.getSession().getTransaction( partition );

         
         try
         {
-            transaction = partition.beginWriteTransaction();
+            if ( transaction == null )
+            {
+                transaction = partition.beginWriteTransaction();
+                
+                if ( moveContext.getSession().hasSessionTransaction() )
+                {
+                    moveContext.getSession().addTransaction( partition, transaction );
+                }
+            }
+        
             moveContext.setTransaction( transaction );
             Entry originalEntry = getOriginalEntry( moveContext );
 
@@ -1242,7 +1290,11 @@ public class DefaultOperationManager implements OperationManager
             Interceptor head = directoryService.getInterceptor( moveContext.getNextInterceptor()
);
 
             head.move( moveContext );
-            transaction.commit();
+            
+            if ( !moveContext.getSession().hasSessionTransaction() )
+            {
+                transaction.commit();
+            }
         }
         catch ( LdapException le )
         {
@@ -1391,13 +1443,23 @@ public class DefaultOperationManager implements OperationManager
         Partition partition = directoryService.getPartitionNexus().getPartition( dn );
         moveAndRenameContext.setPartition( partition );
 
-        PartitionTxn transaction = null; 
-        
         lockWrite();
         
+        // Start a Write transaction right away
+        PartitionTxn transaction = moveAndRenameContext.getSession().getTransaction( partition
); 
+        
         try
         {
-            transaction = partition.beginWriteTransaction();
+            if ( transaction == null )
+            {
+                transaction = partition.beginWriteTransaction();
+                
+                if ( moveAndRenameContext.getSession().hasSessionTransaction() )
+                {
+                    moveAndRenameContext.getSession().addTransaction( partition, transaction
);
+                }
+            }
+
             moveAndRenameContext.setOriginalEntry( getOriginalEntry( moveAndRenameContext
) );
             moveAndRenameContext.setModifiedEntry( moveAndRenameContext.getOriginalEntry().clone()
);
             moveAndRenameContext.setTransaction( transaction );
@@ -1407,7 +1469,10 @@ public class DefaultOperationManager implements OperationManager
 
             head.moveAndRename( moveAndRenameContext );
 
-            transaction.commit();
+            if ( !moveAndRenameContext.getSession().hasSessionTransaction() )
+            {
+                transaction.commit();
+            }
         }
         catch ( LdapException le )
         {
@@ -1548,10 +1613,24 @@ public class DefaultOperationManager implements OperationManager
 
         lockWrite();
 
+        Partition partition = directoryService.getPartitionNexus().getPartition( dn );
+
+        // Start a Write transaction right away
+        PartitionTxn transaction = renameContext.getSession().getTransaction( partition );

+        
         // Call the rename method
         try
         {
-            Partition partition = directoryService.getPartitionNexus().getPartition( dn );
+            if ( transaction == null )
+            {
+                transaction = partition.beginWriteTransaction();
+                
+                if ( renameContext.getSession().hasSessionTransaction() )
+                {
+                    renameContext.getSession().addTransaction( partition, transaction );
+                }
+            }
+
             renameContext.setPartition( partition );
 
             // populate the context with the old entry
@@ -1581,22 +1660,35 @@ public class DefaultOperationManager implements OperationManager
                 }
             }
 
-
             Entry originalEntry = getOriginalEntry( renameContext );
             renameContext.setOriginalEntry( originalEntry );
             renameContext.setModifiedEntry( originalEntry.clone() );
-
-            // Call the Rename method
-            PartitionTxn transaction = null; 
             Interceptor head = directoryService.getInterceptor( renameContext.getNextInterceptor()
);
+
+            // Start a Write transaction right away
+            transaction = renameContext.getSession().getTransaction( partition ); 
             
+            // Call the Rename method
             try
             {
-                transaction = partition.beginWriteTransaction();
+                if ( transaction == null )
+                {
+                    transaction = partition.beginWriteTransaction();
+                    
+                    if ( renameContext.getSession().hasSessionTransaction() )
+                    {
+                        renameContext.getSession().addTransaction( partition, transaction
);
+                    }
+                }
+
                 renameContext.setTransaction( transaction );
 
                 head.rename( renameContext );
-                transaction.commit();
+                
+                if ( !renameContext.getSession().hasSessionTransaction() )
+                {
+                    transaction.commit();
+                }
             }
             catch ( LdapException le )
             {
diff --git a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/StartTransactionHandler.java
b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/StartTransactionHandler.java
new file mode 100644
index 0000000..b79d358
--- /dev/null
+++ b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/StartTransactionHandler.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.server.ldap.handlers.extended;
+
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.extras.extended.startTransaction.StartTransactionRequest;
+import org.apache.directory.api.ldap.extras.extended.startTransaction.StartTransactionResponse;
+import org.apache.directory.api.ldap.extras.extended.startTransaction.StartTransactionResponseImpl;
+import org.apache.directory.server.ldap.ExtendedOperationHandler;
+import org.apache.directory.server.ldap.LdapServer;
+import org.apache.directory.server.ldap.LdapSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An handler to manage the StartTransaction extended request operation
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StartTransactionHandler implements ExtendedOperationHandler<StartTransactionRequest,
StartTransactionResponse>
+{
+    private static final Logger LOG = LoggerFactory.getLogger( StartTransactionHandler.class
);
+    public static final Set<String> EXTENSION_OIDS;
+
+    static
+    {
+        Set<String> set = new HashSet<>( 2 );
+        set.add( StartTransactionRequest.EXTENSION_OID );
+        set.add( StartTransactionResponse.EXTENSION_OID );
+        EXTENSION_OIDS = Collections.unmodifiableSet( set );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return StartTransactionRequest.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handleExtendedOperation( LdapSession requestor, StartTransactionRequest req
) throws Exception
+    {
+        LOG.debug( "StartTransaction requested" );
+        
+        // We need to create a new transaction ID for the current session.
+        // If the current session is already processing a transaction, we will return an
error
+        StartTransactionResponse startTransactionResponse = new StartTransactionResponseImpl();
+        
+        requestor.getCoreSession().beginSessionTransaction();
+
+        // write the response
+        requestor.getIoSession().write( startTransactionResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<String> getExtensionOids()
+    {
+        return EXTENSION_OIDS;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLdapServer( LdapServer ldapServer )
+    {
+    }
+}


Mime
View raw message