You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ka...@apache.org on 2010/09/25 19:54:52 UTC

svn commit: r1001288 - /directory/apacheds/trunk/ldif-partition/src/main/java/org/apache/directory/server/core/partition/ldif/SingleFileLdifPartition.java

Author: kayyagari
Date: Sat Sep 25 17:54:51 2010
New Revision: 1001288

URL: http://svn.apache.org/viewvc?rev=1001288&view=rev
Log:
o used an explicit object as a lock to acheive serialization
o EntryOffset now has a separate comparator impl
o added a method to clear the temporary buffer file
o code formatting

Modified:
    directory/apacheds/trunk/ldif-partition/src/main/java/org/apache/directory/server/core/partition/ldif/SingleFileLdifPartition.java

Modified: directory/apacheds/trunk/ldif-partition/src/main/java/org/apache/directory/server/core/partition/ldif/SingleFileLdifPartition.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/ldif-partition/src/main/java/org/apache/directory/server/core/partition/ldif/SingleFileLdifPartition.java?rev=1001288&r1=1001287&r2=1001288&view=diff
==============================================================================
--- directory/apacheds/trunk/ldif-partition/src/main/java/org/apache/directory/server/core/partition/ldif/SingleFileLdifPartition.java (original)
+++ directory/apacheds/trunk/ldif-partition/src/main/java/org/apache/directory/server/core/partition/ldif/SingleFileLdifPartition.java Sat Sep 25 17:54:51 2010
@@ -25,8 +25,13 @@ import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -77,6 +82,29 @@ public class SingleFileLdifPartition ext
     /** file name of the underlying LDIF store */
     private String fileName;
 
+    /** lock for serializing the operations on the backing LDIF file */
+    private Object lock = new Object();
+
+    /** the list of temporary buffers */
+    private List<File> tempFileList = new ArrayList<File>();
+
+    private Comparator<EntryOffset> comparator = new Comparator<EntryOffset>()
+    {
+        public int compare( EntryOffset o1, EntryOffset o2 )
+        {
+            if ( o1.getEnd() > o2.getEnd() )
+            {
+                return 1;
+            }
+            if ( o1.getEnd() < o2.getEnd() )
+            {
+                return -1;
+            }
+
+            return 0;
+        }
+    };
+
     private static Logger LOG = LoggerFactory.getLogger( SingleFileLdifPartition.class );
 
 
@@ -214,121 +242,147 @@ public class SingleFileLdifPartition ext
 
 
     @Override
-    public synchronized void add( AddOperationContext addContext ) throws LdapException
+    public void add( AddOperationContext addContext ) throws LdapException
     {
-        wrappedPartition.add( addContext );
+        synchronized ( lock )
+        {
+            wrappedPartition.add( addContext );
 
-        Entry entry = addContext.getEntry();
+            Entry entry = addContext.getEntry();
 
-        DN dn = entry.getDn();
-        Long entryId = wrappedPartition.getEntryId( dn );
+            DN dn = entry.getDn();
+            Long entryId = wrappedPartition.getEntryId( dn );
 
-        String ldif = LdifUtils.convertEntryToLdif( entry );
+            String ldif = LdifUtils.convertEntryToLdif( entry );
 
-        try
-        {
-            if ( dn.equals( suffix ) )
+            try
             {
-                contextEntry = entry;
-                appendLdif( entryId, null, ldif );
-                return;
-            }
+                if ( dn.equals( suffix ) )
+                {
+                    contextEntry = entry;
+                    appendLdif( entryId, null, ldif );
+                    return;
+                }
 
-            // entry has a parent
-            Long parentId = wrappedPartition.getEntryId( dn.getParent() );
-            EntryOffset parentOffset = offsetMap.get( parentId );
-            if ( parentOffset.getEnd() == ldifFile.length() )
-            {
-                appendLdif( entryId, parentOffset, ldif );
+                // entry has a parent
+                Long parentId = wrappedPartition.getEntryId( dn.getParent() );
+                EntryOffset parentOffset = offsetMap.get( parentId );
+                if ( parentOffset.getEnd() == ldifFile.length() )
+                {
+                    appendLdif( entryId, parentOffset, ldif );
+                }
+                else
+                {
+                    insertNAppendLdif( entryId, parentOffset, ldif );
+                }
             }
-            else
+            catch ( IOException e )
             {
-                insertNAppendLdif( entryId, parentOffset, ldif );
+                throw new LdapException( e );
             }
         }
-        catch ( IOException e )
-        {
-            throw new LdapException( e );
-        }
     }
 
 
     @Override
-    public synchronized void modify( ModifyOperationContext modifyContext ) throws LdapException
+    public void modify( ModifyOperationContext modifyContext ) throws LdapException
     {
-        wrappedPartition.modify( modifyContext );
+        synchronized ( lock )
+        {
 
-        Entry entry = modifyContext.getAlteredEntry();
+            wrappedPartition.modify( modifyContext );
 
-        DN dn = entry.getDn();
-        Long entryId = wrappedPartition.getEntryId( dn );
+            Entry entry = modifyContext.getAlteredEntry();
 
-        String ldif = LdifUtils.convertEntryToLdif( entry );
+            DN dn = entry.getDn();
+            Long entryId = wrappedPartition.getEntryId( dn );
 
-        replaceLdif( entryId, ldif );
+            String ldif = LdifUtils.convertEntryToLdif( entry );
+
+            replaceLdif( entryId, ldif );
+        }
     }
 
 
     @Override
-    public synchronized void rename( RenameOperationContext renameContext ) throws LdapException
+    public void rename( RenameOperationContext renameContext ) throws LdapException
     {
-        Long id = wrappedPartition.getEntryId( renameContext.getDn() );
-
-        wrappedPartition.rename( renameContext );
-
-        try
+        synchronized ( lock )
         {
-            // perform for the first id
-            Entry entry = wrappedPartition.lookup( id );
-            String ldif = LdifUtils.convertEntryToLdif( entry );
-            replaceLdif( id, ldif );
+            Long id = wrappedPartition.getEntryId( renameContext.getDn() );
 
-            IndexCursor<Long, Entry, Long> cursor = wrappedPartition.getOneLevelIndex().forwardCursor( id );
-            cursor.beforeFirst();
+            wrappedPartition.rename( renameContext );
 
-            while ( cursor.next() )
+            try
             {
-                IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
+                // perform for the first id
+                Entry entry = wrappedPartition.lookup( id );
+                String ldif = LdifUtils.convertEntryToLdif( entry );
+                replaceLdif( id, ldif );
 
-                Long tmpId = idxEntry.getId();
-                entry = wrappedPartition.lookup( tmpId );
-                ldif = LdifUtils.convertEntryToLdif( entry );
-                replaceLdif( tmpId, ldif );
+                IndexCursor<Long, Entry, Long> cursor = wrappedPartition.getOneLevelIndex().forwardCursor( id );
+                cursor.beforeFirst();
 
-                replaceRecursive( tmpId, null );
-            }
+                while ( cursor.next() )
+                {
+                    IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
 
-            cursor.close();
-        }
-        catch ( Exception e )
-        {
-            throw new LdapException( e );
+                    Long tmpId = idxEntry.getId();
+                    entry = wrappedPartition.lookup( tmpId );
+                    ldif = LdifUtils.convertEntryToLdif( entry );
+                    replaceLdif( tmpId, ldif );
+
+                    replaceRecursive( tmpId, null );
+                }
+
+                cursor.close();
+            }
+            catch ( Exception e )
+            {
+                e.printStackTrace();
+                System.exit( 0 );
+                throw new LdapException( e );
+            }
         }
     }
 
 
     @Override
-    public synchronized void move( MoveOperationContext moveContext ) throws LdapException
+    public void move( MoveOperationContext moveContext ) throws LdapException
     {
-        Long entryId = wrappedPartition.getEntryId( moveContext.getDn() );
+        //        String threadName = Thread.currentThread().getName();
+        //        System.out.println( threadName + " is trying to get lock on move method" );
+        synchronized ( lock )
+        {
+            //System.out.println( threadName + " GOT lock on move method " + moveContext.getDn() );
+            Long entryId = wrappedPartition.getEntryId( moveContext.getDn() );
+
+            wrappedPartition.move( moveContext );
+
+            Long parentId = wrappedPartition.getEntryId( moveContext.getNewSuperior() );
 
-        wrappedPartition.move( moveContext );
-        
-        move( entryId );
+            move( entryId, parentId );
+        }
     }
 
 
     @Override
     public void moveAndRename( MoveAndRenameOperationContext opContext ) throws LdapException
     {
-        Long entryId = wrappedPartition.getEntryId( opContext.getDn() );
-        
-        wrappedPartition.moveAndRename( opContext );
-        
-        move( entryId );
+        synchronized ( lock )
+        {
+
+            Long entryId = wrappedPartition.getEntryId( opContext.getDn() );
+
+            wrappedPartition.moveAndRename( opContext );
+
+            Long parentId = wrappedPartition.getEntryId( opContext.getNewSuperiorDn() );
+
+            move( entryId, parentId );
+        }
     }
 
-    
+
     /**
      * 
      * changes the LDIF entry content changed as part of move or moveAndRename
@@ -337,189 +391,185 @@ public class SingleFileLdifPartition ext
      * FIXME explain in detail the algorithm used to perform move inside the LDIF file
      * 
      * @param entryId the moved entry's ID
+     * @param parentId the moved entry's new parent id
      * @throws LdapException
      */
-    private synchronized void move( Long entryId ) throws LdapException
+    private synchronized void move( Long entryId, Long parentId ) throws LdapException
     {
-        try
+        synchronized ( lock )
         {
-            IndexCursor<Long, Entry, Long> cursor = wrappedPartition.getSubLevelIndex().forwardCursor( entryId );
-            cursor.beforeFirst();
+            try
+            {
+                EntryOffset entryOffset = offsetMap.get( entryId );
 
-            Set<EntryOffset> sortedOffSets = new TreeSet<EntryOffset>();
+                // delete the entries which were moved in the wrapped parttion
+                IndexCursor<Long, Entry, Long> cursor = wrappedPartition.getSubLevelIndex().forwardCursor( entryId );
+                cursor.beforeFirst();
 
-            while ( cursor.next() )
-            {
-                IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
-                sortedOffSets.add( offsetMap.get( idxEntry.getId() ) );
-            }
+                Set<EntryOffset> movedTreeOffsets = new TreeSet<EntryOffset>( comparator );
 
-            cursor.close();
+                while ( cursor.next() )
+                {
+                    EntryOffset o = offsetMap.get( cursor.get().getId() );
+                    movedTreeOffsets.add( o );
+                }
 
-            EntryOffset[] offsetArray = sortedOffSets.toArray( new EntryOffset[0] );
-            EntryOffset endOffset = offsetArray[offsetArray.length - 1];
+                cursor.close();
 
-            long count = ( ldifFile.length() - endOffset.getEnd() );
+                EntryOffset[] movedTreeOffsetArray = movedTreeOffsets.toArray( new EntryOffset[0] );
+                EntryOffset endMovOffset = movedTreeOffsetArray[movedTreeOffsetArray.length - 1];
 
-            FileChannel tmpBufChannel = createTempBuf();
-            FileChannel mainChannel = ldifFile.getChannel();
-            
-            mainChannel.transferTo( endOffset.getEnd(), count, tmpBufChannel );
-            ldifFile.setLength( offsetArray[0].getStart() );
-            
-            Set<EntryOffset> belowEntryOffsets = greaterThan( endOffset );
-            
-            long diff = -( endOffset.getEnd() - offsetArray[0].getStart() ); // diff should be marked negative
-            
-            for ( EntryOffset o : belowEntryOffsets )
-            {
-                o.changeOffsetsBy( diff );
-            }
-            
-            tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
-            tmpBufChannel.truncate( 0 );
+                long count = ( ldifFile.length() - endMovOffset.getEnd() );
 
-            DN dnAfterMove = wrappedPartition.getEntryDn( entryId );
-            Long parentId = wrappedPartition.getEntryId( dnAfterMove.getParent() );
-            EntryOffset aboveOffset = offsetMap.get( parentId );
-            
-            Set<EntryOffset> middleOffsets = greaterThan( aboveOffset );
-            middleOffsets.removeAll( sortedOffSets );
-            
+                File tmpFile = File.createTempFile( "mov", ".ldif" );
 
-            File tmpFile = File.createTempFile( "ldifpartition", ".buf" );
-            tmpFile.deleteOnExit();
+                RandomAccessFile tmpMovFile = new RandomAccessFile( tmpFile.getAbsolutePath(), "rws" );
 
-            RandomAccessFile tmpMovFile = new RandomAccessFile( tmpFile.getAbsolutePath(), "rws" );
-            tmpMovFile.setLength( 0 );
+                FileChannel tempBuf = tmpMovFile.getChannel();
+                FileChannel mainChannel = ldifFile.getChannel();
+                tempBuf.truncate( 0 );
+                if ( count > 0 )
+                {
+                    mainChannel.transferTo( endMovOffset.getEnd(), count, tempBuf );
+                    ldifFile.setLength( movedTreeOffsetArray[0].getStart() ); // delete the now obsolete(cause of move operation) entries
 
-            // perform for the first id
-            Entry entry = wrappedPartition.lookup( entryId );
-            String ldif = LdifUtils.convertEntryToLdif( entry );
-            
-            long pos = tmpMovFile.getFilePointer();
-            tmpMovFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
+                    tempBuf.transferTo( 0, tempBuf.size(), mainChannel );
+                    tempBuf.truncate( 0 );
+                    tmpMovFile.setLength( 0 );
+
+                    EntryOffset[] belowOffsets = greaterThan( endMovOffset );
+                    EntryOffset aboveOffset = getAboveEntry( movedTreeOffsetArray[0] );
+
+                    for ( EntryOffset o : belowOffsets )
+                    {
+                        Long id = o.getId();
+
+                        o = new EntryOffset( id, aboveOffset.getEnd(), aboveOffset.getEnd() + o.length() );
+                        offsetMap.put( id, o );
+                        aboveOffset = o;
+                    }
+                }
+                else
+                // in case if nothing exists after the moving tree
+                {
+                    ldifFile.setLength( movedTreeOffsetArray[0].getStart() );
+                }
 
-            EntryOffset entryOffset = new EntryOffset( entryId, pos, tmpMovFile.getFilePointer() );
-            offsetMap.put( entryId, entryOffset );
+                EntryOffset tmpMovFileOffset = null;
+                for ( EntryOffset o : movedTreeOffsets )
+                {
+                    Long childId = o.getId();
+                    Entry entry = wrappedPartition.lookup( childId );
+                    String ldif = LdifUtils.convertEntryToLdif( entry );
+
+                    long pos = tmpMovFile.getFilePointer();
+                    tmpMovFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
+
+                    entryOffset = new EntryOffset( childId, pos, tmpMovFile.getFilePointer() );
+                    offsetMap.put( childId, entryOffset );
+                    tmpMovFileOffset = entryOffset;
+                }
 
-            cursor = wrappedPartition.getOneLevelIndex().forwardCursor( entryId );
-            cursor.beforeFirst();
+                EntryOffset parentOffset = offsetMap.get( parentId );
+                count = ( ldifFile.length() - parentOffset.getEnd() );
 
-            while ( cursor.next() )
-            {
-                IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
+                EntryOffset[] belowParentOffsets = greaterThan( parentOffset );
+
+                if ( count > 0 )
+                {
+                    mainChannel.transferTo( parentOffset.getEnd(), count, tempBuf );
+                }
+
+                ldifFile.setLength( parentOffset.getEnd() );
+
+                // copy back to main file
+                tempBuf.transferTo( 0, tempBuf.size(), mainChannel );
+                tempBuf.truncate( 0 );
+                tmpFile.delete();
+
+                // change offset of the copied entries
+                Set<Long> idset = new HashSet<Long>();
+                for ( EntryOffset o : movedTreeOffsets )
+                {
+                    o = new EntryOffset( o.getId(), parentOffset.getEnd(), parentOffset.getEnd() + o.length() );
+                    offsetMap.put( o.getId(), o );
+                    parentOffset = o;
+                    idset.add( o.getId() );
+                }
 
-                Long childId = idxEntry.getId();
-                entry = wrappedPartition.lookup( childId );
-                ldif = LdifUtils.convertEntryToLdif( entry );
-                
-                pos = tmpMovFile.getFilePointer();
-                tmpMovFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
-
-                entryOffset = new EntryOffset( childId, pos, tmpMovFile.getFilePointer() );
-                offsetMap.put( childId, entryOffset );
-
-                appendRecursive( childId, null, tmpMovFile );
-            }
-
-            cursor.close();
-
-            count = ( ldifFile.length() - aboveOffset.getEnd() );
-            
-            mainChannel.transferTo( endOffset.getEnd(), count, tmpBufChannel );
-            ldifFile.setLength( aboveOffset.getEnd() );
-            
-            FileChannel tmpMovChannel = tmpMovFile.getChannel();
-            tmpMovChannel.transferTo( 0, tmpMovChannel.size(), mainChannel );
-            tmpMovChannel.truncate( 0 );
-            
-            EntryOffset prevOffset = aboveOffset;
-            // now reset the offsets of the moved entries
-            for ( EntryOffset o : offsetArray )
-            {
-                // get each EentryOffset object from map, cause the objects
-                // present in this array now point to old offset objects
-                
-                Long curId = o.getId();
-                EntryOffset newOffset = offsetMap.get( curId );
-                
-                Long prevEnd = prevOffset.getEnd();
-                
-                EntryOffset latestOffset = new EntryOffset( curId, prevEnd, prevEnd + newOffset.length() );
-                offsetMap.put( curId, latestOffset );
-                
-                prevOffset = latestOffset;
-            }
-
-            // now copy the contents from temp buf
-            
-            tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
-            tmpBufChannel.truncate( 0 );
-            
-            for( EntryOffset o : middleOffsets )
-            {
-                Long curId = o.getId();
-                Long prevEnd = prevOffset.getEnd();
-                EntryOffset latestOffset = new EntryOffset( curId, prevEnd + o.getStart(), prevEnd + o.length() );
-                offsetMap.put( curId, latestOffset );
-                
-                prevOffset = latestOffset;
+                for ( EntryOffset o : belowParentOffsets )
+                {
+                    Long tmpId = o.getId();
+                    if ( idset.contains( tmpId ) )
+                    {
+                        continue;
+                    }
+
+                    o = new EntryOffset( tmpId, parentOffset.getEnd(), parentOffset.getEnd() + o.length() );
+                    offsetMap.put( tmpId, o );
+                    parentOffset = o;
+                    idset.add( o.getId() );
+                }
+
+                deleteTempFiles();
+            }
+            catch ( Exception e )
+            {
+                throw new LdapException( e );
             }
-            
-            //System.out.println( prevOffset.getEnd() == ldifFile.length() );
-        }
-        catch ( Exception e )
-        {
-            throw new LdapException( e );
         }
     }
 
+
     @Override
-    public synchronized void delete( Long id ) throws LdapException
+    public void delete( Long id ) throws LdapException
     {
-        wrappedPartition.delete( id );
-
-        try
+        synchronized ( lock )
         {
-            EntryOffset entryOffset = offsetMap.get( id );
+            wrappedPartition.delete( id );
 
-            // check if the entry to be removed is present at the end of file
-            if ( entryOffset.getEnd() == ldifFile.length() )
+            try
             {
-                ldifFile.setLength( entryOffset.getStart() );
-                // check if entry is the context entry
-                if ( entryOffset.getStart() == 0 )
+                EntryOffset entryOffset = offsetMap.get( id );
+
+                // check if the entry to be removed is present at the end of file
+                if ( entryOffset.getEnd() == ldifFile.length() )
                 {
-                    contextEntry = null;
+                    ldifFile.setLength( entryOffset.getStart() );
+                    // check if entry is the context entry
+                    if ( entryOffset.getStart() == 0 )
+                    {
+                        contextEntry = null;
+                    }
                 }
-            }
-            else
-            {
-                FileChannel tmpBufChannel = createTempBuf();
-                FileChannel mainChannel = ldifFile.getChannel();
+                else
+                {
+                    FileChannel tmpBufChannel = createTempBuf();
+                    FileChannel mainChannel = ldifFile.getChannel();
 
-                long count = ( ldifFile.length() - entryOffset.getEnd() );
+                    long count = ( ldifFile.length() - entryOffset.getEnd() );
 
-                mainChannel.transferTo( entryOffset.getEnd(), count, tmpBufChannel );
-                ldifFile.setLength( entryOffset.getStart() );
+                    mainChannel.transferTo( entryOffset.getEnd(), count, tmpBufChannel );
+                    ldifFile.setLength( entryOffset.getStart() );
 
-                Set<EntryOffset> belowParentOffsets = greaterThan( entryOffset );
+                    EntryOffset[] belowParentOffsets = greaterThan( entryOffset );
 
-                long diff = - ( entryOffset.length() ); // this offset change should always be negative
+                    long diff = -( entryOffset.length() ); // this offset change should always be negative
 
-                for ( EntryOffset o : belowParentOffsets )
-                {
-                    o.changeOffsetsBy( diff );
-                }
+                    for ( EntryOffset o : belowParentOffsets )
+                    {
+                        o.changeOffsetsBy( diff );
+                    }
 
-                tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
-                tmpBufChannel.truncate( 0 );
+                    tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
+                    tmpBufChannel.truncate( 0 );
+                    deleteTempFiles();
+                }
+            }
+            catch ( IOException e )
+            {
+                throw new LdapException( e );
             }
-        }
-        catch ( IOException e )
-        {
-            throw new LdapException( e );
         }
     }
 
@@ -535,16 +585,20 @@ public class SingleFileLdifPartition ext
 
     private EntryOffset getAboveEntry( EntryOffset offset ) throws LdapException
     {
-        for ( EntryOffset e : offsetMap.values() )
+        synchronized ( lock )
         {
-            if ( e.getEnd() == offset.getStart() )
+
+            for ( EntryOffset e : offsetMap.values() )
             {
-                return e;
+                if ( e.getEnd() == offset.getStart() )
+                {
+                    return e;
+                }
             }
-        }
 
-        // if non exists
-        return null;
+            // if non exists
+            return null;
+        }
     }
 
 
@@ -557,43 +611,47 @@ public class SingleFileLdifPartition ext
      */
     private void replaceRecursive( Long id, Map<Long, IndexCursor<Long, Entry, Long>> cursorMap ) throws Exception
     {
-        IndexCursor<Long, Entry, Long> cursor = null;
-        if ( cursorMap == null )
+        synchronized ( lock )
         {
-            cursorMap = new HashMap<Long, IndexCursor<Long, Entry, Long>>();
-        }
 
-        cursor = cursorMap.get( id );
+            IndexCursor<Long, Entry, Long> cursor = null;
+            if ( cursorMap == null )
+            {
+                cursorMap = new HashMap<Long, IndexCursor<Long, Entry, Long>>();
+            }
 
-        if ( cursor == null )
-        {
-            cursor = wrappedPartition.getOneLevelIndex().forwardCursor( id );
-            cursor.beforeFirst();
-            cursorMap.put( id, cursor );
-        }
+            cursor = cursorMap.get( id );
 
-        if ( !cursor.next() ) // if this is a leaf entry's DN
-        {
-            cursorMap.remove( id );
-            cursor.close();
-        }
-        else
-        {
-            do
+            if ( cursor == null )
             {
-                IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
-                Entry entry = wrappedPartition.lookup( idxEntry.getId() );
+                cursor = wrappedPartition.getOneLevelIndex().forwardCursor( id );
+                cursor.beforeFirst();
+                cursorMap.put( id, cursor );
+            }
 
-                Long entryId = wrappedPartition.getEntryId( entry.getDn() );
-                String ldif = LdifUtils.convertEntryToLdif( entry );
+            if ( !cursor.next() ) // if this is a leaf entry's DN
+            {
+                cursorMap.remove( id );
+                cursor.close();
+            }
+            else
+            {
+                do
+                {
+                    IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
+                    Entry entry = wrappedPartition.lookup( idxEntry.getId() );
+
+                    Long entryId = wrappedPartition.getEntryId( entry.getDn() );
+                    String ldif = LdifUtils.convertEntryToLdif( entry );
 
-                replaceLdif( entryId, ldif );
+                    replaceLdif( entryId, ldif );
 
-                replaceRecursive( entryId, cursorMap );
+                    replaceRecursive( entryId, cursorMap );
+                }
+                while ( cursor.next() );
+                cursorMap.remove( id );
+                cursor.close();
             }
-            while ( cursor.next() );
-            cursorMap.remove( id );
-            cursor.close();
         }
     }
 
@@ -606,53 +664,58 @@ public class SingleFileLdifPartition ext
      * @param tmpMovFile a RandomAccessFile to be used as temporary buffer
      * @throws Exception
      */
-    private void appendRecursive( Long entryId, Map<Long, IndexCursor<Long, Entry, Long>> cursorMap, RandomAccessFile tmpMovFile ) throws Exception
+    private void appendRecursive( Long entryId, Map<Long, IndexCursor<Long, Entry, Long>> cursorMap,
+        RandomAccessFile tmpMovFile ) throws Exception
     {
-        IndexCursor<Long, Entry, Long> cursor = null;
-        if ( cursorMap == null )
+        synchronized ( lock )
         {
-            cursorMap = new HashMap<Long, IndexCursor<Long, Entry, Long>>();
-        }
 
-        cursor = cursorMap.get( entryId );
+            IndexCursor<Long, Entry, Long> cursor = null;
+            if ( cursorMap == null )
+            {
+                cursorMap = new HashMap<Long, IndexCursor<Long, Entry, Long>>();
+            }
 
-        if ( cursor == null )
-        {
-            cursor = wrappedPartition.getOneLevelIndex().forwardCursor( entryId );
-            cursor.beforeFirst();
-            cursorMap.put( entryId, cursor );
-        }
+            cursor = cursorMap.get( entryId );
 
-        if ( !cursor.next() ) // if this is a leaf entry's DN
-        {
-            cursorMap.remove( entryId );
-            cursor.close();
-        }
-        else
-        {
-            do
+            if ( cursor == null )
             {
-                IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
-                Entry entry = wrappedPartition.lookup( idxEntry.getId() );
+                cursor = wrappedPartition.getOneLevelIndex().forwardCursor( entryId );
+                cursor.beforeFirst();
+                cursorMap.put( entryId, cursor );
+            }
 
-                Long childId = wrappedPartition.getEntryId( entry.getDn() );
-                String ldif = LdifUtils.convertEntryToLdif( entry );
+            if ( !cursor.next() ) // if this is a leaf entry's DN
+            {
+                cursorMap.remove( entryId );
+                cursor.close();
+            }
+            else
+            {
+                do
+                {
+                    IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
+                    Entry entry = wrappedPartition.lookup( idxEntry.getId() );
+
+                    Long childId = wrappedPartition.getEntryId( entry.getDn() );
+                    String ldif = LdifUtils.convertEntryToLdif( entry );
 
-                long pos = tmpMovFile.getFilePointer();
-                tmpMovFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
+                    long pos = tmpMovFile.getFilePointer();
+                    tmpMovFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
 
-                EntryOffset entryOffset = new EntryOffset( childId, pos, tmpMovFile.getFilePointer() );
-                offsetMap.put( childId, entryOffset );
+                    EntryOffset entryOffset = new EntryOffset( childId, pos, tmpMovFile.getFilePointer() );
+                    offsetMap.put( childId, entryOffset );
 
-                appendRecursive( childId, cursorMap, tmpMovFile );
+                    appendRecursive( childId, cursorMap, tmpMovFile );
+                }
+                while ( cursor.next() );
+                cursorMap.remove( entryId );
+                cursor.close();
             }
-            while ( cursor.next() );
-            cursorMap.remove( entryId );
-            cursor.close();
         }
     }
 
-    
+
     /**
      * inserts a given LDIF entry in the middle of the LDIF entries
      *
@@ -664,38 +727,43 @@ public class SingleFileLdifPartition ext
     private void insertNAppendLdif( Long entryId, EntryOffset aboveEntryOffset, String ldif )
         throws LdapException
     {
-        if ( aboveEntryOffset == null )
+        synchronized ( lock )
         {
-            throw new IllegalStateException( "parent offset is null" );
-        }
+            if ( aboveEntryOffset == null )
+            {
+                throw new IllegalStateException( "parent offset is null" );
+            }
 
-        try
-        {
-            FileChannel tmpBufChannel = createTempBuf();
-            FileChannel mainChannel = ldifFile.getChannel();
+            try
+            {
+                FileChannel tmpBufChannel = createTempBuf();
+                FileChannel mainChannel = ldifFile.getChannel();
 
-            long count = ( ldifFile.length() - aboveEntryOffset.getEnd() );
+                long count = ( ldifFile.length() - aboveEntryOffset.getEnd() );
 
-            mainChannel.transferTo( aboveEntryOffset.getEnd(), count, tmpBufChannel );
-            ldifFile.setLength( aboveEntryOffset.getEnd() );
+                mainChannel.transferTo( aboveEntryOffset.getEnd(), count, tmpBufChannel );
+                ldifFile.setLength( aboveEntryOffset.getEnd() );
 
-            Set<EntryOffset> belowParentOffsets = greaterThan( aboveEntryOffset );
+                EntryOffset[] belowParentOffsets = greaterThan( aboveEntryOffset );
 
-            EntryOffset entryOffset = appendLdif( entryId, aboveEntryOffset, ldif );
+                EntryOffset entryOffset = appendLdif( entryId, aboveEntryOffset, ldif );
 
-            long diff = entryOffset.length();
+                long diff = entryOffset.length();
 
-            for ( EntryOffset o : belowParentOffsets )
+                for ( EntryOffset o : belowParentOffsets )
+                {
+                    o.changeOffsetsBy( diff );
+                }
+
+                tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
+                tmpBufChannel.truncate( 0 );
+
+                deleteTempFiles();
+            }
+            catch ( IOException e )
             {
-                o.changeOffsetsBy( diff );
+                throw new LdapException( e );
             }
-
-            tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
-            tmpBufChannel.truncate( 0 );
-        }
-        catch ( IOException e )
-        {
-            throw new LdapException( e );
         }
     }
 
@@ -709,60 +777,66 @@ public class SingleFileLdifPartition ext
      */
     private void replaceLdif( Long entryId, String ldif ) throws LdapException
     {
-        try
+        synchronized ( lock )
         {
-            EntryOffset entryOffset = offsetMap.get( entryId );
-            byte[] utf8Data = StringTools.getBytesUtf8( ldif + "\n" );
-            long fileLen = ldifFile.length();
-            long diff = utf8Data.length - entryOffset.length();
-
-            // check if modified entry occupies the same space
-            if ( diff == 0 )
-            {
-                ldifFile.seek( entryOffset.getStart() );
-                ldifFile.write( utf8Data );
-            }
-            else if ( fileLen == entryOffset.getEnd() ) // modified entry is at the end of file
+            //System.out.println( "replaceLdif called by " + Thread.currentThread().getName() );
+            try
             {
-                ldifFile.setLength( entryOffset.getStart() );
-                ldifFile.write( utf8Data );
+                EntryOffset entryOffset = offsetMap.get( entryId );
+                byte[] utf8Data = StringTools.getBytesUtf8( ldif + "\n" );
+                long fileLen = ldifFile.length();
+                long diff = utf8Data.length - entryOffset.length();
 
-                fileLen = ldifFile.length();
-
-                // change the offsets, the modified entry size changed
-                if ( fileLen != entryOffset.getEnd() )
+                // check if modified entry occupies the same space
+                if ( diff == 0 )
                 {
-                    entryOffset = new EntryOffset( entryId, entryOffset.getStart(), fileLen );
-                    offsetMap.put( entryId, entryOffset );
+                    ldifFile.seek( entryOffset.getStart() );
+                    ldifFile.write( utf8Data );
                 }
-            }
-            else
-            // modified entry size got changed and is in the middle somewhere
-            {
-                FileChannel tmpBufChannel = createTempBuf();
-                FileChannel mainChannel = ldifFile.getChannel();
+                else if ( fileLen == entryOffset.getEnd() ) // modified entry is at the end of file
+                {
+                    ldifFile.setLength( entryOffset.getStart() );
+                    ldifFile.write( utf8Data );
 
-                long count = ( ldifFile.length() - entryOffset.getEnd() );
+                    fileLen = ldifFile.length();
 
-                mainChannel.transferTo( entryOffset.getEnd(), count, tmpBufChannel );
-                ldifFile.setLength( entryOffset.getStart() );
+                    // change the offsets, the modified entry size changed
+                    if ( fileLen != entryOffset.getEnd() )
+                    {
+                        entryOffset = new EntryOffset( entryId, entryOffset.getStart(), fileLen );
+                        offsetMap.put( entryId, entryOffset );
+                    }
+                }
+                else
+                // modified entry size got changed and is in the middle somewhere
+                {
+                    FileChannel tmpBufChannel = createTempBuf();
+                    FileChannel mainChannel = ldifFile.getChannel();
 
-                Set<EntryOffset> belowParentOffsets = greaterThan( entryOffset );
+                    long count = ( ldifFile.length() - entryOffset.getEnd() );
 
-                entryOffset = appendLdif( entryId, getAboveEntry( entryOffset ), ldif );
+                    mainChannel.transferTo( entryOffset.getEnd(), count, tmpBufChannel );
+                    ldifFile.setLength( entryOffset.getStart() );
 
-                for ( EntryOffset o : belowParentOffsets )
-                {
-                    o.changeOffsetsBy( diff );
-                }
+                    EntryOffset[] belowParentOffsets = greaterThan( entryOffset );
 
-                tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
-                tmpBufChannel.truncate( 0 );
+                    entryOffset = appendLdif( entryId, getAboveEntry( entryOffset ), ldif );
+
+                    for ( EntryOffset o : belowParentOffsets )
+                    {
+                        o.changeOffsetsBy( diff );
+                    }
+
+                    tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
+                    tmpBufChannel.truncate( 0 );
+
+                    deleteTempFiles();
+                }
+            }
+            catch ( IOException e )
+            {
+                throw new LdapException( e );
             }
-        }
-        catch ( IOException e )
-        {
-            throw new LdapException( e );
         }
     }
 
@@ -778,32 +852,35 @@ public class SingleFileLdifPartition ext
     private EntryOffset appendLdif( Long entryId, EntryOffset aboveEntryOffset, String ldif )
         throws LdapException
     {
-        try
+        synchronized ( lock )
         {
-            long pos = 0L;
-
-            if ( aboveEntryOffset != null )
-            {
-                pos = aboveEntryOffset.getEnd();
-            }
-            else
+            try
             {
-                // erase file
-                ldifFile.setLength( 0 );
-            }
+                long pos = 0L;
+
+                if ( aboveEntryOffset != null )
+                {
+                    pos = aboveEntryOffset.getEnd();
+                }
+                else
+                {
+                    // erase file
+                    ldifFile.setLength( 0 );
+                }
 
-            ldifFile.seek( pos );
+                ldifFile.seek( pos );
 
-            ldifFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
+                ldifFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
 
-            EntryOffset entryOffset = new EntryOffset( entryId, pos, ldifFile.getFilePointer() );
-            offsetMap.put( entryId, entryOffset );
+                EntryOffset entryOffset = new EntryOffset( entryId, pos, ldifFile.getFilePointer() );
+                offsetMap.put( entryId, entryOffset );
 
-            return entryOffset;
-        }
-        catch ( IOException e )
-        {
-            throw new LdapException( e );
+                return entryOffset;
+            }
+            catch ( IOException e )
+            {
+                throw new LdapException( e );
+            }
         }
     }
 
@@ -868,19 +945,49 @@ public class SingleFileLdifPartition ext
      * 
      * @return a sorted set of EntryOffset objects
      */
-    private Set<EntryOffset> greaterThan( EntryOffset mark )
+    private EntryOffset[] greaterThan( EntryOffset mark )
     {
-        Set<EntryOffset> gtSet = new TreeSet<EntryOffset>();
-
-        for ( EntryOffset o : offsetMap.values() )
+        synchronized ( lock )
         {
-            if ( o.getStart() > mark.getStart() )
+
+            Set<EntryOffset> gtSet = new TreeSet<EntryOffset>( comparator );
+
+            for ( EntryOffset o : offsetMap.values() )
             {
-                gtSet.add( o );
+                if ( o.getStart() > mark.getStart() )
+                {
+                    gtSet.add( o );
+                }
             }
+
+            EntryOffset[] array = gtSet.toArray( new EntryOffset[0] );
+            Arrays.sort( array, comparator );
+
+            return array;
         }
+    }
 
-        return gtSet;
+
+    private EntryOffset[] getBetween( EntryOffset topMark, EntryOffset bottomMmark )
+    {
+        synchronized ( lock )
+        {
+
+            Set<EntryOffset> gtSet = new TreeSet<EntryOffset>( comparator );
+
+            for ( EntryOffset o : offsetMap.values() )
+            {
+                if ( ( o.getStart() > topMark.getStart() ) && ( o.getEnd() < bottomMmark.getEnd() ) )
+                {
+                    gtSet.add( o );
+                }
+            }
+
+            EntryOffset[] array = gtSet.toArray( new EntryOffset[0] );
+            Arrays.sort( array, comparator );
+
+            return array;
+        }
     }
 
 
@@ -905,21 +1012,39 @@ public class SingleFileLdifPartition ext
     /** a temporary file used for swapping contents while performing update operations */
     private FileChannel createTempBuf() throws IOException
     {
-        File tmpFile = File.createTempFile( "ldifpartition", ".buf" );
-        tmpFile.deleteOnExit();
+        synchronized ( lock )
+        {
+            File tmpFile = File.createTempFile( "ldifpartition", ".buf" );
 
-        RandomAccessFile tempBufFile = new RandomAccessFile( tmpFile.getAbsolutePath(), "rws" );
-        tempBufFile.setLength( 0 );
+            RandomAccessFile tempBufFile = new RandomAccessFile( tmpFile.getAbsolutePath(), "rws" );
+            tempBufFile.setLength( 0 );
 
-        return tempBufFile.getChannel();
+            return tempBufFile.getChannel();
+        }
+    }
+
+
+    /**
+     * clears the temp files used as temporary randomaccess buffers
+     */
+    private void deleteTempFiles()
+    {
+        synchronized ( lock )
+        {
+            for ( File f : tempFileList )
+            {
+                f.delete();
+            }
+        }
     }
 }
 
+
 /**
  * a holder class for containing an entry's start and end offset positions
  * in the LDIF file
  */
-class EntryOffset implements Comparable<EntryOffset>
+class EntryOffset
 {
     /** starting position */
     private long start;
@@ -939,21 +1064,6 @@ class EntryOffset implements Comparable<
     }
 
 
-    public int compareTo( EntryOffset o )
-    {
-        if ( end > o.end )
-        {
-            return 1;
-        }
-        else if ( end < o.end )
-        {
-            return -1;
-        }
-
-        return 0;
-    }
-
-
     public long getStart()
     {
         return start;