You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by sa...@apache.org on 2011/12/08 12:13:23 UTC

svn commit: r1211829 - in /directory/apacheds/branches/apacheds-txns: core-avl/src/main/java/org/apache/directory/server/core/avltree/ core-shared/src/main/java/org/apache/directory/server/core/shared/partition/ core-shared/src/main/java/org/apache/dir...

Author: saya
Date: Thu Dec  8 11:13:23 2011
New Revision: 1211829

URL: http://svn.apache.org/viewvc?rev=1211829&view=rev
Log:
Added a background thread to flush the txns from the unflushed part of the txn log to the partitions. For now the thread just wakes up with a predetermined interval and flushes the txns. Could be improved to be woken up only when enough data in logs accumulate.

Added JdbmStoreTxnTest and AvlPartitionTxnTest. Easier to test txns at this level. Added txn demarcation to groups of ldap operations and tests concurrent searches to see they see consistent data and code can handle multiple thread. More tests like these should be added. 

Added:
    directory/apacheds/branches/apacheds-txns/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmStoreTxnTest.java
    directory/apacheds/branches/apacheds-txns/xdbm-partition/src/test/java/org/apache/directory/server/xdbm/impl/avl/AvlPartitionTxnTest.java
Modified:
    directory/apacheds/branches/apacheds-txns/core-avl/src/main/java/org/apache/directory/server/core/avltree/OrderedSetMarshaller.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/DefaultTxnManager.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/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchPerfIT.java

Modified: directory/apacheds/branches/apacheds-txns/core-avl/src/main/java/org/apache/directory/server/core/avltree/OrderedSetMarshaller.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-avl/src/main/java/org/apache/directory/server/core/avltree/OrderedSetMarshaller.java?rev=1211829&r1=1211828&r2=1211829&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-avl/src/main/java/org/apache/directory/server/core/avltree/OrderedSetMarshaller.java (original)
+++ directory/apacheds/branches/apacheds-txns/core-avl/src/main/java/org/apache/directory/server/core/avltree/OrderedSetMarshaller.java Thu Dec  8 11:13:23 2011
@@ -30,7 +30,7 @@ import java.util.Iterator;
 import org.apache.directory.server.i18n.I18n;
 import org.apache.directory.shared.util.Strings;
 
-public class OrderedSetMarshaller<V>
+public class OrderedSetMarshaller<V> implements Marshaller<OrderedSet<V>>
 {
     /** used for serialized form of an empty AvlTree */
     private static final byte[] EMPTY_SET = new byte[1];

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=1211829&r1=1211828&r2=1211829&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 Thu Dec  8 11:13:23 2011
@@ -2091,7 +2091,7 @@ public class DefaultOperationExecutionMa
             entry = originalEntry.clone();
         }
 
-        Dn updn = entry.getDn();
+        Dn updn = originalEntry.getDn();
 
         newRdn.apply( schemaManager );
 

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=1211829&r1=1211828&r2=1211829&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 Thu Dec  8 11:13:23 2011
@@ -20,7 +20,7 @@
 package org.apache.directory.server.core.shared.txn;
 
 
-import org.apache.directory.server.core.api.partition.index.Serializer;
+import org.apache.directory.server.core.api.partition.Partition;
 import org.apache.directory.server.core.api.txn.TxnConflictException;
 import org.apache.directory.server.core.api.txn.TxnLogManager;
 import org.apache.directory.server.core.shared.txn.logedit.TxnStateChange;
@@ -29,11 +29,13 @@ import org.apache.directory.server.core.
 import java.io.ByteArrayOutputStream;
 import java.io.ObjectOutputStream;
 
-import java.util.Comparator;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -72,6 +74,30 @@ class DefaultTxnManager implements TxnMa
 
     /** Latest flushed txn's logical commit time */
     private AtomicLong latestFlushedTxnLSN = new AtomicLong( LogAnchor.UNKNOWN_LSN );
+    
+    /** Default flush interval in ms */
+    private final static int DEFAULT_FLUSH_INTERVAL = 100;
+    
+    /** Flush interval */
+    private int flushInterval;
+    
+    /** Flush lock */
+    private Lock flushLock = new ReentrantLock();
+    
+    /** Flush Condition object */
+    private Condition flushCondition = flushLock.newCondition();
+    
+    /** Whether flushing is failed */
+    private boolean flushFailed;
+    
+    /** partitions to be synced after applying changes */
+    private HashSet<Partition> flushedToPartitions = new HashSet<Partition>();
+    
+    /** Backgorund syncing thread */
+    LogSyncer syncer;
+    
+    /** Initial committed txn */
+    ReadWriteTxn dummyTxn = new ReadWriteTxn();
 
     /** Per thread txn context */
     static final ThreadLocal<Transaction> txnVar =
@@ -86,7 +112,10 @@ class DefaultTxnManager implements TxnMa
 
 
     /**
-     * TODO : doco
+     * Inits the txn manager. A dummy txn is put to the committed queue for read
+     * only txns to bump the ref count so that we can always keep track of the
+     * minimum existing txn.
+     * 
      * @param txnLogManager
      * @param idComparator
      * @param idSerializer
@@ -94,6 +123,16 @@ class DefaultTxnManager implements TxnMa
     public void init( TxnLogManager txnLogManager )
     {
         this.txnLogManager = txnLogManager;
+        flushInterval = DEFAULT_FLUSH_INTERVAL;
+        
+        dummyTxn.commitTxn( LogAnchor.UNKNOWN_LSN );
+        latestCommittedTxn.set( dummyTxn );
+        latestVerifiedTxn.set( dummyTxn );
+        committedQueue.offer( dummyTxn );
+        
+        syncer = new LogSyncer();
+        syncer.setDaemon( true );
+        syncer.start();
     }
 
 
@@ -132,6 +171,11 @@ class DefaultTxnManager implements TxnMa
         {
             throw new IllegalStateException( " trying to commit non existent txn " );
         }
+        
+        if ( flushFailed )
+        {
+            throw new IOException( "Flushing of txns failed" );
+        }
 
         prepareForEndingTxn( txn );
 
@@ -363,7 +407,7 @@ class DefaultTxnManager implements TxnMa
             {
                 toCheck = it.next();
 
-                if ( toCheck.commitTime <= flushedLSN )
+                if ( toCheck.commitTime <= flushedLSN && toCheck != lastTxnToCheck )
                 {
                     it.remove();
                 }
@@ -565,4 +609,105 @@ class DefaultTxnManager implements TxnMa
         logRecord.setData( data, data.length );
         txnLogManager.log( logRecord, false );
     }
+    
+   /**
+    *  Flush the changes of the txns in the committed queue. A txn is flushed
+    *  only if flushing it will not cause a pending txn to see changes beyond its
+    *  start time.
+    *  throws Exception thrown if anything goes wrong during flush.
+    *
+    */
+   private void flushTxns() throws Exception
+   {
+       // If flushing failed already, dont do anything anymore
+       if ( flushFailed )
+       {
+           return;
+       }
+       
+       /*
+        * First get the latest committed txn ref and then the iterator.
+        * Order is important.
+        */
+       ReadWriteTxn latestCommitted = latestCommittedTxn.get();
+       long latestFlushedLsn = latestFlushedTxnLSN.get();
+       flushedToPartitions.clear();
+       
+       Iterator<ReadWriteTxn> it = committedQueue.iterator();
+       ReadWriteTxn txnToFlush;
+       
+       while ( it.hasNext() )
+       {
+           txnToFlush = it.next();
+           
+           if ( txnToFlush.getCommitTime() > latestFlushedLsn )
+           {
+               // Apply changes
+               txnToFlush.flushLogEdits( flushedToPartitions );
+               
+               latestFlushedTxnLSN.set( txnToFlush.getCommitTime() );
+           }
+           
+           if ( txnToFlush == latestCommitted )
+           {
+               // leave latest committed txn in queue and dont go beyond it.
+               break;
+           }
+           
+           
+           /*
+            *  If the latest flushed txn has ref count > 0, then
+            *  following txns wont be flushed yet.
+            */
+           
+           if ( txnToFlush.getRefCount().get() >  0 )
+           {
+               break;
+           }
+           
+           // Remove from the queue
+           it.remove();
+       }
+       
+       // Sync each flushed to partition
+       Iterator<Partition> partitionIt = flushedToPartitions.iterator();
+       
+       while ( partitionIt.hasNext() )
+       {
+           partitionIt.next().sync();
+       }
+           
+   }
+    
+    class LogSyncer extends Thread 
+    {
+
+        @Override
+        public void run() 
+        {
+            try
+            {
+
+                flushLock.lock();
+
+                while ( !this.isInterrupted() )
+                {
+                    flushCondition.await( flushInterval, TimeUnit.MILLISECONDS );
+                    flushTxns();
+                }
+
+            }
+            catch ( InterruptedException e )
+            {
+                // Bail out
+            }
+            catch ( Exception e )
+            {
+                e.printStackTrace();
+                flushFailed = true;
+            }
+        }
+      }
+    
+    
 }

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=1211829&r1=1211828&r2=1211829&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 Thu Dec  8 11:13:23 2011
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.LinkedList;
 import java.util.Iterator;
 import java.util.NavigableSet;
+import java.util.Set;
 import java.util.TreeSet;
 import java.util.Map;
 import java.util.HashMap;
@@ -31,29 +32,23 @@ import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.Comparator;
 
-import org.apache.directory.server.core.api.txn.logedit.EntryModification;
 import org.apache.directory.server.core.api.txn.logedit.LogEdit;
 import org.apache.directory.server.core.shared.txn.logedit.IndexChange;
 import org.apache.directory.server.core.api.txn.logedit.DataChange;
-import org.apache.directory.server.core.shared.txn.logedit.EntryAddDelete;
-import org.apache.directory.server.core.shared.txn.logedit.EntryChange;
 import org.apache.directory.server.core.shared.txn.logedit.DataChangeContainer;
 
 import org.apache.directory.server.core.api.log.UserLogRecord;
 
+import org.apache.directory.server.core.api.partition.Partition;
 import org.apache.directory.server.core.api.partition.index.ForwardIndexEntry;
 import org.apache.directory.server.core.api.partition.index.ReverseIndexEntry;
-import org.apache.directory.server.core.api.partition.index.IndexComparator;
 import org.apache.directory.server.core.api.partition.index.IndexEntry;
 import org.apache.directory.server.core.api.partition.index.Index;
-import org.apache.directory.server.core.api.partition.index.IndexCursor;
 import org.apache.directory.server.core.api.partition.index.UUIDComparator;
 
 import org.apache.directory.shared.ldap.model.name.Dn;
-import org.apache.directory.shared.ldap.model.entry.AttributeUtils;
 import org.apache.directory.shared.ldap.model.entry.Entry;
 
-import org.apache.directory.shared.ldap.model.exception.LdapException;
 
 import org.apache.directory.shared.ldap.model.message.SearchScope;
 
@@ -677,4 +672,24 @@ import org.apache.directory.shared.ldap.
 
         return result;
     }
+    
+    
+    public void flushLogEdits( Set<Partition> affectedPartitions ) throws Exception
+    {
+        Iterator<LogEdit> it = logEdits.iterator();
+        LogEdit edit;
+        
+        
+        while ( it.hasNext() )
+        {
+            edit = it.next();
+            
+            edit.apply( false );
+            
+            if ( edit instanceof DataChangeContainer )
+            {
+                affectedPartitions.add( ( ( DataChangeContainer ) edit ).getPartition() );
+            }
+        }
+    }
 }

Added: directory/apacheds/branches/apacheds-txns/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmStoreTxnTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmStoreTxnTest.java?rev=1211829&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmStoreTxnTest.java (added)
+++ directory/apacheds/branches/apacheds-txns/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmStoreTxnTest.java Thu Dec  8 11:13:23 2011
@@ -0,0 +1,259 @@
+
+package org.apache.directory.server.core.partition.impl.btree.jdbm;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.Random;
+import java.util.UUID;
+
+import javax.naming.directory.SearchControls;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.server.constants.ApacheSchemaConstants;
+import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.api.partition.OperationExecutionManager;
+import org.apache.directory.server.core.api.partition.index.IndexCursor;
+import org.apache.directory.server.core.api.txn.TxnManager;
+import org.apache.directory.server.core.shared.partition.OperationExecutionManagerFactory;
+import org.apache.directory.server.core.shared.txn.TxnManagerFactory;
+import org.apache.directory.server.xdbm.XdbmStoreUtils;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.csn.CsnFactory;
+import org.apache.directory.shared.ldap.model.entry.DefaultEntry;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.PresenceNode;
+import org.apache.directory.shared.ldap.model.message.AliasDerefMode;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.schemaextractor.SchemaLdifExtractor;
+import org.apache.directory.shared.ldap.schemaextractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.shared.ldap.schemaloader.LdifSchemaLoader;
+import org.apache.directory.shared.ldap.schemamanager.impl.DefaultSchemaManager;
+import org.apache.directory.shared.util.Strings;
+import org.apache.directory.shared.util.exception.Exceptions;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class JdbmStoreTxnTest
+{
+    static File wkdir;
+    static JdbmPartition store;
+    private static SchemaManager schemaManager = null;
+    private static LdifSchemaLoader loader;
+    
+    /** Operation execution manager */
+    private static OperationExecutionManager executionManager;
+
+    /** Txn manager */
+    private static TxnManager txnManager;
+    
+    /** log dir */
+    private static File logDir;
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        String workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = JdbmStoreTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        
+        logDir = new File( workingDirectory + File.separatorChar + "txnlog" + File.separatorChar );
+        logDir.mkdirs();
+        TxnManagerFactory.init( logDir.getPath(), 1 << 13, 1 << 14 );
+        OperationExecutionManagerFactory.init();
+        executionManager = OperationExecutionManagerFactory.instance();
+        txnManager = TxnManagerFactory.txnManagerInstance();
+
+        File schemaRepository = new File( workingDirectory, "schema" );
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy( true );
+        loader = new LdifSchemaLoader( schemaRepository );
+        schemaManager = new DefaultSchemaManager( loader );
+
+        boolean loaded = schemaManager.loadAllEnabled();
+
+        if ( !loaded )
+        {
+            fail( "Schema load failed : " + Exceptions.printErrors(schemaManager.getErrors()) );
+        }
+    }
+
+
+    @Before
+    public void createStore() throws Exception
+    {
+        // setup the working directory for the store
+        wkdir = File.createTempFile( getClass().getSimpleName(), "db" );
+        wkdir.delete();
+        wkdir = new File( wkdir.getParentFile(), getClass().getSimpleName() );
+        
+        // initialize the store
+        store = new JdbmPartition( schemaManager );
+        store.setId( "example" );
+        store.setCacheSize( 10 );
+        store.setPartitionPath( wkdir.toURI() );
+        store.setSyncOnWrite( false );
+
+        JdbmIndex ouIndex = new JdbmIndex( SchemaConstants.OU_AT_OID );
+        ouIndex.setWkDirPath( wkdir.toURI() );
+        store.addIndex( ouIndex );
+        
+        JdbmIndex uidIndex = new JdbmIndex( SchemaConstants.UID_AT_OID );
+        uidIndex.setWkDirPath( wkdir.toURI() );
+        store.addIndex( uidIndex );
+
+        Dn suffixDn = new Dn( schemaManager, "o=Good Times Co." );
+        store.setSuffixDn( suffixDn );
+
+        store.initialize();
+
+        XdbmStoreUtils.loadExampleData( store, schemaManager );
+    }
+
+
+    @After
+    public void destroyStore() throws Exception
+    {
+        if ( store != null )
+        {
+            // make sure all files are closed so that they can be deleted on Windows.
+            store.destroy();
+        }
+
+        store = null;
+        
+        if ( logDir != null )
+        {
+            FileUtils.deleteDirectory( logDir);
+        }
+
+        if ( wkdir != null )
+        {
+            FileUtils.deleteDirectory( wkdir );
+        }
+
+        wkdir = null;
+    }
+    
+    @Test
+    public void testAddsConcurrentWithSearch()
+    {
+        try
+        {
+            int numThreads = 10;
+            AddsConcurrentWithSearchTestThread threads[] = new AddsConcurrentWithSearchTestThread[numThreads];
+            
+            
+            for ( int idx =0; idx < numThreads; idx++ )
+            {
+                threads[idx] = new AddsConcurrentWithSearchTestThread();
+                threads[idx].start();
+            }
+            
+            txnManager.beginTransaction( false );
+            
+            // dn id 12
+            Dn martinDn = new Dn( schemaManager, "cn=Marting King,ou=Sales,o=Good Times Co." );
+            DefaultEntry entry = new DefaultEntry( schemaManager, martinDn );
+            entry.add( "objectClass", "top", "person", "organizationalPerson" );
+            entry.add( "ou", "Sales" );
+            entry.add( "cn", "Martin King" );
+            entry.add( "entryCSN", new CsnFactory( 1 ).newInstance().toString() );
+            entry.add( "entryUUID", Strings.getUUIDString( 12 ).toString() );
+
+            AddOperationContext addContext = new AddOperationContext( null, entry );
+            executionManager.add( store, addContext );
+            
+            // Sleep some
+            Thread.sleep( 100 );
+            
+            // dn id 13
+            Dn jimmyDn = new Dn( schemaManager, "cn=Jimmy Wales, ou=Sales,o=Good Times Co." );
+            entry = new DefaultEntry( schemaManager, jimmyDn );
+            entry.add( "objectClass", "top", "person", "organizationalPerson" );
+            entry.add( "ou", "Marketing" );
+            entry.add( "cn", "Jimmy Wales" );
+            entry.add( "entryCSN", new CsnFactory( 1 ).newInstance().toString() );
+            entry.add( "entryUUID", Strings.getUUIDString( 13 ).toString() );
+            
+            addContext = new AddOperationContext( null, entry );
+            executionManager.add( store, addContext );
+            
+            txnManager.commitTransaction();
+            
+            for ( int idx =0; idx < numThreads; idx++ )
+            {
+                threads[idx].join();
+            }
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            assertTrue( false );
+        }
+    }
+    
+    
+    class AddsConcurrentWithSearchTestThread extends Thread
+    {
+        private void doSearch() throws Exception
+        {
+            int numEntries = 0;
+            
+            SearchControls controls = new SearchControls();
+            controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
+            ExprNode filter = new PresenceNode( schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT ) );
+            
+            Dn baseDn = new Dn( schemaManager, "ou=Sales,o=Good Times Co." );
+            
+            txnManager.beginTransaction( true );
+
+            IndexCursor<UUID> cursor = store.getSearchEngine().cursor( baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
+            
+            while ( cursor.next() )
+            {
+                numEntries++;
+            }
+            
+            assertTrue( numEntries == 2 || numEntries == 4 );
+            //System.out.println("Num entries: " + numEntries );
+            
+            txnManager.commitTransaction();
+        }
+
+
+        public void run()
+        {         
+            try
+            {
+                Random sleepRandomizer = new Random();
+                int sleepTime = sleepRandomizer.nextInt( 10 ) * 100;
+                
+                Thread.sleep( sleepTime );
+                
+                doSearch();
+            }
+            catch( Exception e )
+            {
+                e.printStackTrace();
+                fail();
+                assertTrue( false );
+            }
+            
+            
+            
+        }
+    } // end of class RemoveInsertTestThread
+
+}

Modified: directory/apacheds/branches/apacheds-txns/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchPerfIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchPerfIT.java?rev=1211829&r1=1211828&r2=1211829&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchPerfIT.java (original)
+++ directory/apacheds/branches/apacheds-txns/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchPerfIT.java Thu Dec  8 11:13:23 2011
@@ -51,7 +51,7 @@ public class SearchPerfIT extends Abstra
     /**
      * test a search request perf.
      */
-    @Test
+   // @Test
     public void testSearchRequestPerf() throws Exception
     {
         //getLdapServer().getDirectoryService().getInterceptorChain().addFirst( new TimerInterceptor( "Start" ) );

Added: directory/apacheds/branches/apacheds-txns/xdbm-partition/src/test/java/org/apache/directory/server/xdbm/impl/avl/AvlPartitionTxnTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/xdbm-partition/src/test/java/org/apache/directory/server/xdbm/impl/avl/AvlPartitionTxnTest.java?rev=1211829&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/xdbm-partition/src/test/java/org/apache/directory/server/xdbm/impl/avl/AvlPartitionTxnTest.java (added)
+++ directory/apacheds/branches/apacheds-txns/xdbm-partition/src/test/java/org/apache/directory/server/xdbm/impl/avl/AvlPartitionTxnTest.java Thu Dec  8 11:13:23 2011
@@ -0,0 +1,292 @@
+
+package org.apache.directory.server.xdbm.impl.avl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.Semaphore;
+
+import javax.naming.directory.SearchControls;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
+import org.apache.directory.server.core.api.partition.OperationExecutionManager;
+import org.apache.directory.server.core.api.partition.index.Index;
+import org.apache.directory.server.core.api.partition.index.IndexCursor;
+import org.apache.directory.server.core.api.txn.TxnManager;
+import org.apache.directory.server.core.partition.impl.avl.AvlPartition;
+import org.apache.directory.server.core.shared.partition.OperationExecutionManagerFactory;
+import org.apache.directory.server.core.shared.txn.TxnManagerFactory;
+import org.apache.directory.server.xdbm.XdbmStoreUtils;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.csn.CsnFactory;
+import org.apache.directory.shared.ldap.model.entry.DefaultEntry;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.PresenceNode;
+import org.apache.directory.shared.ldap.model.message.AliasDerefMode;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.schemaextractor.SchemaLdifExtractor;
+import org.apache.directory.shared.ldap.schemaextractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.shared.ldap.schemaloader.LdifSchemaLoader;
+import org.apache.directory.shared.ldap.schemamanager.impl.DefaultSchemaManager;
+import org.apache.directory.shared.util.Strings;
+import org.apache.directory.shared.util.exception.Exceptions;
+
+import org.junit.Rule;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class AvlPartitionTxnTest
+{
+    private static AvlPartition partition;
+    private static SchemaManager schemaManager = null;
+
+    
+    /** Operation execution manager */
+    private static OperationExecutionManager executionManager;
+
+    /** Txn manager */
+    private static TxnManager txnManager;
+    
+    /** log dir */
+    private static File logDir;
+    
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        String workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = AvlPartitionTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+        
+        logDir = new File( workingDirectory + File.separatorChar + "txnlog" + File.separatorChar );
+        logDir.mkdirs();
+        TxnManagerFactory.init( logDir.getPath(), 1 << 13, 1 << 14 );
+        OperationExecutionManagerFactory.init();
+        executionManager = OperationExecutionManagerFactory.instance();
+        txnManager = TxnManagerFactory.txnManagerInstance();
+
+        File schemaRepository = new File( workingDirectory, "schema" );
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy( true );
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+
+        schemaManager = new DefaultSchemaManager( loader );
+
+        boolean loaded = schemaManager.loadAllEnabled();
+
+        if ( !loaded )
+        {
+            fail( "Schema load failed : " + Exceptions.printErrors(schemaManager.getErrors()) );
+        }
+    }
+
+
+    @Before
+    public void createStore() throws Exception
+    {
+        // initialize the partition
+        partition = new AvlPartition( schemaManager );
+        partition.setId( "example" );
+        partition.setSyncOnWrite( false );
+
+        partition.addIndex( new AvlIndex( SchemaConstants.OU_AT_OID ) );
+        partition.addIndex( new AvlIndex( SchemaConstants.UID_AT_OID ) );
+        partition.setSuffixDn( new Dn( schemaManager, "o=Good Times Co." ) );
+
+        partition.initialize();
+
+        try
+        {
+            txnManager.beginTransaction( false );
+            XdbmStoreUtils.loadExampleData( partition, schemaManager );
+            txnManager.commitTransaction();
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail();
+        }
+    }
+   
+
+    @After
+    public void destroyStore() throws Exception
+    {
+        partition.destroy();
+        
+        if ( logDir != null )
+        {
+            FileUtils.deleteDirectory( logDir);
+        }
+    }
+    
+    
+    @Test
+    public void testAddsConcurrentWithSearch()
+    {
+        try
+        {
+            int numThreads = 10;
+            AddsConcurrentWithSearchTestThread threads[] = new AddsConcurrentWithSearchTestThread[numThreads];
+            
+            
+            for ( int idx =0; idx < numThreads; idx++ )
+            {
+                threads[idx] = new AddsConcurrentWithSearchTestThread();
+                threads[idx].start();
+            }
+            
+            txnManager.beginTransaction( false );
+            
+            // dn id 12
+            Dn martinDn = new Dn( schemaManager, "cn=Marting King,ou=Sales,o=Good Times Co." );
+            DefaultEntry entry = new DefaultEntry( schemaManager, martinDn );
+            entry.add( "objectClass", "top", "person", "organizationalPerson" );
+            entry.add( "ou", "Sales" );
+            entry.add( "cn", "Martin King" );
+            entry.add( "entryCSN", new CsnFactory( 1 ).newInstance().toString() );
+            entry.add( "entryUUID", Strings.getUUIDString( 12 ).toString() );
+
+            AddOperationContext addContext = new AddOperationContext( null, entry );
+            executionManager.add( partition, addContext );
+            
+            // Sleep some
+            Thread.sleep( 100 );
+            
+            // dn id 13
+            Dn jimmyDn = new Dn( schemaManager, "cn=Jimmy Wales, ou=Sales,o=Good Times Co." );
+            entry = new DefaultEntry( schemaManager, jimmyDn );
+            entry.add( "objectClass", "top", "person", "organizationalPerson" );
+            entry.add( "ou", "Marketing" );
+            entry.add( "cn", "Jimmy Wales" );
+            entry.add( "entryCSN", new CsnFactory( 1 ).newInstance().toString() );
+            entry.add( "entryUUID", Strings.getUUIDString( 13 ).toString() );
+            
+            addContext = new AddOperationContext( null, entry );
+            executionManager.add( partition, addContext );
+            
+            txnManager.commitTransaction();
+            
+            for ( int idx =0; idx < numThreads; idx++ )
+            {
+                threads[idx].join();
+            }
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            assertTrue( false );
+        }
+    }
+    
+
+    private static boolean removeDirectory( File directory )
+    {
+        if ( directory == null )
+        {
+            return false;
+        }
+        
+        if ( !directory.exists() )
+        {
+            return true;
+        }
+        
+        if ( !directory.isDirectory() )
+        {
+            return false;   
+        }
+            
+
+        String[] list = directory.list();
+        
+        if ( list != null )
+        {
+            for ( int i = 0; i < list.length; i++ )
+            {
+                File entry = new File( directory, list[i] );
+
+                if ( entry.isDirectory() )
+                {
+                    if ( !removeDirectory( entry ) )
+                        return false;
+                }
+                else
+                {
+                    if ( !entry.delete() )
+                        return false;
+                }
+            }
+        }
+
+        return directory.delete();
+    }
+    
+    class AddsConcurrentWithSearchTestThread extends Thread
+    {
+        private void doSearch() throws Exception
+        {
+            int numEntries = 0;
+            
+            SearchControls controls = new SearchControls();
+            controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
+            ExprNode filter = new PresenceNode( schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT ) );
+            
+            Dn baseDn = new Dn( schemaManager, "ou=Sales,o=Good Times Co." );
+            
+            txnManager.beginTransaction( true );
+
+            IndexCursor<UUID> cursor = partition.getSearchEngine().cursor( baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls );
+            
+            while ( cursor.next() )
+            {
+                numEntries++;
+            }
+            
+            assertTrue( numEntries == 2 || numEntries == 4 );
+            //System.out.println("Num entries: " + numEntries );
+            
+            txnManager.commitTransaction();
+        }
+
+
+        public void run()
+        {         
+            try
+            {
+                Random sleepRandomizer = new Random();
+                int sleepTime = sleepRandomizer.nextInt( 10 ) * 100;
+                
+                Thread.sleep( sleepTime );
+                
+                doSearch();
+            }
+            catch( Exception e )
+            {
+                e.printStackTrace();
+                fail();
+                assertTrue( false );
+            }
+            
+            
+            
+        }
+    } // end of class RemoveInsertTestThread
+
+}