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/27 19:54:11 UTC

svn commit: r1001839 - in /directory/apacheds/trunk/ldif-partition/src: main/java/org/apache/directory/server/core/partition/ldif/SingleFileLdifPartition.java test/java/org/apache/directory/server/core/partition/SingleFileLdifPartitionTest.java

Author: kayyagari
Date: Mon Sep 27 17:54:10 2010
New Revision: 1001839

URL: http://svn.apache.org/viewvc?rev=1001839&view=rev
Log:
o replaced the logic for writing the partition data back to file
  (this new logic is quite simple and rude, this just dumps the partition data back to disk whenever an update happens,
   this makes the user's life more simple while editing the config by hand(there were some issues with the earlier impl if a user includes a comment in the config)
   Note: comments cannot be retained after an update operation)
o fixed the tests and added a new test 

Modified:
    directory/apacheds/trunk/ldif-partition/src/main/java/org/apache/directory/server/core/partition/ldif/SingleFileLdifPartition.java
    directory/apacheds/trunk/ldif-partition/src/test/java/org/apache/directory/server/core/partition/SingleFileLdifPartitionTest.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=1001839&r1=1001838&r2=1001839&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 Mon Sep 27 17:54:10 2010
@@ -24,15 +24,9 @@ package org.apache.directory.server.core
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
-import java.nio.channels.FileChannel;
-import java.util.Arrays;
-import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
 import java.util.UUID;
 
 import javax.naming.InvalidNameException;
@@ -53,11 +47,9 @@ import org.apache.directory.shared.ldap.
 import org.apache.directory.shared.ldap.entry.Entry;
 import org.apache.directory.shared.ldap.exception.LdapException;
 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
-import org.apache.directory.shared.ldap.ldif.LdapLdifException;
 import org.apache.directory.shared.ldap.ldif.LdifEntry;
 import org.apache.directory.shared.ldap.ldif.LdifReader;
 import org.apache.directory.shared.ldap.ldif.LdifUtils;
-import org.apache.directory.shared.ldap.name.DN;
 import org.apache.directory.shared.ldap.util.StringTools;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -74,8 +66,11 @@ public class SingleFileLdifPartition ext
     /** the LDIF file holding the partition's data */
     private RandomAccessFile ldifFile;
 
-    /** offset map for entries in the ldif file */
-    Map<Long, EntryOffset> offsetMap = new HashMap<Long, EntryOffset>();
+    /** flag to enable/disable re-writing in-memory partition data back to file, default is set to true */
+    private volatile boolean enableRewriting = true;
+
+    /** flag used internally to detect if partition data was updated in memory but not on disk */
+    private boolean dirty = false;
 
     /** file name of the underlying LDIF store */
     private String fileName;
@@ -83,26 +78,6 @@ public class SingleFileLdifPartition ext
     /** lock for serializing the operations on the backing LDIF file */
     private Object lock = new Object();
 
-    /** the list of temporary buffers */
-    private Map<File,RandomAccessFile> tempBufMap = new HashMap<File,RandomAccessFile>();
-
-    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 );
 
 
@@ -123,7 +98,7 @@ public class SingleFileLdifPartition ext
         {
             ldifFile = new RandomAccessFile( file, "rws" );
             fileName = file;
-            
+
             File partitionDir = new File( file ).getParentFile();
             setPartitionDir( partitionDir );
             setWorkingDirectory( partitionDir.getAbsolutePath() );
@@ -173,17 +148,17 @@ public class SingleFileLdifPartition ext
     {
         // partition directory will always be the directory
         // in which the backing LDIF file is present 
-        if( getPartitionDir() != null )
+        if ( getPartitionDir() != null )
         {
             super.setPartitionDir( partitionDir );
         }
     }
 
-    
+
     @Override
     public void setWorkingDirectory( String workingDirectory )
     {
-        if( getWorkingDirectory() != null )
+        if ( getWorkingDirectory() != null )
         {
             super.setWorkingDirectory( workingDirectory );
         }
@@ -205,9 +180,6 @@ public class SingleFileLdifPartition ext
             return;
         }
 
-        long curEnryStart = 0;
-        long curEntryEnd = parser.prevEntryEnd;
-
         LdifEntry ldifEntry = itr.next();
 
         contextEntry = new DefaultEntry( schemaManager, ldifEntry.getEntry() );
@@ -218,41 +190,20 @@ public class SingleFileLdifPartition ext
         {
             addMandatoryOpAt( contextEntry );
             store.add( contextEntry );
-
-            Long entryId = ( Long ) store.getEntryId( suffix );
-            EntryOffset entryOffset = new EntryOffset( entryId, curEnryStart, curEntryEnd );
-
-            offsetMap.put( entryId, entryOffset );
         }
         else
         {
             throw new LdapException( "The given LDIF file doesn't contain the context entry" );
         }
 
-        curEnryStart = curEntryEnd;
-        curEntryEnd = parser.prevEntryEnd;
-
         while ( itr.hasNext() )
         {
-            long tmpStart = curEnryStart;
-            long tmpEnd = curEntryEnd;
-
             ldifEntry = itr.next();
 
-            curEnryStart = curEntryEnd;
-            curEntryEnd = parser.prevEntryEnd;
-
             Entry entry = new DefaultEntry( schemaManager, ldifEntry.getEntry() );
 
-            curEntryEnd = ldifFile.getFilePointer();
-
             addMandatoryOpAt( entry );
             store.add( entry );
-
-            Long entryId = ( Long ) store.getEntryId( entry.getDn() );
-            EntryOffset offset = new EntryOffset( entryId, tmpStart, tmpEnd );
-
-            offsetMap.put( entryId, offset );
         }
 
         parser.close();
@@ -272,38 +223,18 @@ public class SingleFileLdifPartition ext
         {
             wrappedPartition.add( addContext );
 
-            Entry entry = addContext.getEntry();
-
-            DN dn = entry.getDn();
-            Long entryId = wrappedPartition.getEntryId( dn );
-
-            String ldif = LdifUtils.convertEntryToLdif( entry );
-
-            try
+            if ( contextEntry == null )
             {
-                if ( dn.equals( suffix ) )
-                {
-                    contextEntry = entry;
-                    appendLdif( entryId, null, ldif );
-                    return;
-                }
+                Entry entry = addContext.getEntry();
 
-                // entry has a parent
-                Long parentId = wrappedPartition.getEntryId( dn.getParent() );
-                EntryOffset parentOffset = offsetMap.get( parentId );
-                if ( parentOffset.getEnd() == ldifFile.length() )
+                if ( entry.getDn().equals( suffix ) )
                 {
-                    appendLdif( entryId, parentOffset, ldif );
-                }
-                else
-                {
-                    insertNAppendLdif( entryId, parentOffset, ldif );
+                    contextEntry = entry;
                 }
             }
-            catch ( IOException e )
-            {
-                throw new LdapException( e );
-            }
+
+            dirty = true;
+            rewritePartitionData();
         }
     }
 
@@ -314,15 +245,8 @@ public class SingleFileLdifPartition ext
         synchronized ( lock )
         {
             wrappedPartition.modify( modifyContext );
-
-            Entry entry = modifyContext.getAlteredEntry();
-
-            DN dn = entry.getDn();
-            Long entryId = wrappedPartition.getEntryId( dn );
-
-            String ldif = LdifUtils.convertEntryToLdif( entry );
-
-            replaceLdif( entryId, ldif );
+            dirty = true;
+            rewritePartitionData();
         }
     }
 
@@ -332,38 +256,9 @@ public class SingleFileLdifPartition ext
     {
         synchronized ( lock )
         {
-            Long id = wrappedPartition.getEntryId( renameContext.getDn() );
-
             wrappedPartition.rename( renameContext );
-
-            try
-            {
-                // perform for the first id
-                Entry entry = wrappedPartition.lookup( id );
-                String ldif = LdifUtils.convertEntryToLdif( entry );
-                replaceLdif( id, ldif );
-
-                IndexCursor<Long, Entry, Long> cursor = wrappedPartition.getOneLevelIndex().forwardCursor( id );
-                cursor.beforeFirst();
-
-                while ( cursor.next() )
-                {
-                    IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
-
-                    Long tmpId = idxEntry.getId();
-                    entry = wrappedPartition.lookup( tmpId );
-                    ldif = LdifUtils.convertEntryToLdif( entry );
-                    replaceLdif( tmpId, ldif );
-
-                    replaceRecursive( tmpId, null );
-                }
-
-                cursor.close();
-            }
-            catch ( Exception e )
-            {
-                throw new LdapException( e );
-            }
+            dirty = true;
+            rewritePartitionData();
         }
     }
 
@@ -373,13 +268,9 @@ public class SingleFileLdifPartition ext
     {
         synchronized ( lock )
         {
-            Long entryId = wrappedPartition.getEntryId( moveContext.getDn() );
-
             wrappedPartition.move( moveContext );
-
-            Long parentId = wrappedPartition.getEntryId( moveContext.getNewSuperior() );
-
-            move( entryId, parentId );
+            dirty = true;
+            rewritePartitionData();
         }
     }
 
@@ -389,150 +280,9 @@ public class SingleFileLdifPartition ext
     {
         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
-     * operations 
-     * 
-     * 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, Long parentId ) throws LdapException
-    {
-        synchronized ( lock )
-        {
-            try
-            {
-                EntryOffset entryOffset = offsetMap.get( entryId );
-
-                // delete the entries which were moved in the wrapped parttion
-                IndexCursor<Long, Entry, Long> cursor = wrappedPartition.getSubLevelIndex().forwardCursor( entryId );
-                cursor.beforeFirst();
-
-                Set<EntryOffset> movedTreeOffsets = new TreeSet<EntryOffset>( comparator );
-
-                while ( cursor.next() )
-                {
-                    EntryOffset o = offsetMap.get( cursor.get().getId() );
-                    movedTreeOffsets.add( o );
-                }
-
-                cursor.close();
-
-                EntryOffset[] movedTreeOffsetArray = movedTreeOffsets.toArray( new EntryOffset[0] );
-                EntryOffset endMovOffset = movedTreeOffsetArray[movedTreeOffsetArray.length - 1];
-
-                long count = ( ldifFile.length() - endMovOffset.getEnd() );
-
-                RandomAccessFile tmpMovFile = createTempFile();
-
-                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
-
-                    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() );
-                }
-
-                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 );
-                }
-
-                EntryOffset parentOffset = offsetMap.get( parentId );
-                count = ( ldifFile.length() - parentOffset.getEnd() );
-
-                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 );
-
-                // 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() );
-                }
-
-                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() );
-                }
-            }
-            catch ( Exception e )
-            {
-                throw new LdapException( e );
-            }
-            finally
-            {
-                deleteTempFiles();
-            }
+            dirty = true;
+            rewritePartitionData();
         }
     }
 
@@ -543,53 +293,8 @@ public class SingleFileLdifPartition ext
         synchronized ( lock )
         {
             wrappedPartition.delete( id );
-
-            try
-            {
-                EntryOffset entryOffset = offsetMap.get( id );
-
-                // check if the entry to be removed is present at the end of file
-                if ( entryOffset.getEnd() == ldifFile.length() )
-                {
-                    ldifFile.setLength( entryOffset.getStart() );
-                    // check if entry is the context entry
-                    if ( entryOffset.getStart() == 0 )
-                    {
-                        contextEntry = null;
-                    }
-                }
-                else
-                {
-                    RandomAccessFile tempBufFile = createTempFile();
-                    FileChannel tmpBufChannel = tempBufFile.getChannel();
-                    FileChannel mainChannel = ldifFile.getChannel();
-
-                    long count = ( ldifFile.length() - entryOffset.getEnd() );
-
-                    mainChannel.transferTo( entryOffset.getEnd(), count, tmpBufChannel );
-                    ldifFile.setLength( entryOffset.getStart() );
-
-                    EntryOffset[] belowParentOffsets = greaterThan( entryOffset );
-
-                    long diff = -( entryOffset.length() ); // this offset change should always be negative
-
-                    for ( EntryOffset o : belowParentOffsets )
-                    {
-                        o.changeOffsetsBy( diff );
-                    }
-
-                    tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
-                    tmpBufChannel.truncate( 0 );
-                }
-            }
-            catch ( IOException e )
-            {
-                throw new LdapException( e );
-            }
-            finally
-            {
-                deleteTempFiles();
-            }
+            dirty = true;
+            rewritePartitionData();
         }
     }
 
@@ -603,74 +308,59 @@ public class SingleFileLdifPartition ext
     }
 
 
-    private EntryOffset getAboveEntry( EntryOffset offset ) throws LdapException
+    /**
+     * writes the partition's data to the file if {@link #enableRewriting} is set to true
+     * and partition was modified since the last write or {@link #dirty} data. 
+     * 
+     * @throws LdapException
+     */
+    private void rewritePartitionData() throws LdapException
     {
         synchronized ( lock )
         {
-
-            for ( EntryOffset e : offsetMap.values() )
+            if ( !enableRewriting || !dirty )
             {
-                if ( e.getEnd() == offset.getStart() )
-                {
-                    return e;
-                }
+                return;
             }
 
-            // if non exists
-            return null;
-        }
-    }
+            try
+            {
+                ldifFile.setLength( 0 ); // wipe the file clean
 
+                Long suffixId = wrappedPartition.getEntryId( suffix );
 
-    /**
-     * replaces entries present at ONE level scope of a parent entry in a recursive manner
-     *
-     * @param id the parent entry's id
-     * @param cursorMap the map which holds open cursors
-     * @throws Exception
-     */
-    private void replaceRecursive( Long id, Map<Long, IndexCursor<Long, Entry, Long>> cursorMap ) throws Exception
-    {
-        synchronized ( lock )
-        {
-
-            IndexCursor<Long, Entry, Long> cursor = null;
-            if ( cursorMap == null )
-            {
-                cursorMap = new HashMap<Long, IndexCursor<Long, Entry, Long>>();
-            }
+                if( suffixId == null )
+                {
+                    contextEntry = null;
+                    return;
+                }
+                
+                IndexCursor<Long, Entry, Long> cursor = wrappedPartition.getOneLevelIndex().forwardCursor( suffixId );
 
-            cursor = cursorMap.get( id );
 
-            if ( cursor == null )
-            {
-                cursor = wrappedPartition.getOneLevelIndex().forwardCursor( id );
-                cursor.beforeFirst();
-                cursorMap.put( id, cursor );
-            }
+                appendLdif( wrappedPartition.lookup( suffixId ) );
 
-            if ( !cursor.next() ) // if this is a leaf entry's DN
-            {
-                cursorMap.remove( id );
-                cursor.close();
-            }
-            else
-            {
-                do
+                while ( cursor.next() )
                 {
-                    IndexEntry<Long, Entry, Long> idxEntry = cursor.get();
-                    Entry entry = wrappedPartition.lookup( idxEntry.getId() );
+                    Long childId = cursor.get().getId();
 
-                    Long entryId = wrappedPartition.getEntryId( entry.getDn() );
-                    String ldif = LdifUtils.convertEntryToLdif( entry );
+                    Entry entry = wrappedPartition.lookup( childId );
 
-                    replaceLdif( entryId, ldif );
+                    appendLdif( entry );
 
-                    replaceRecursive( entryId, cursorMap );
+                    appendRecursive( childId, null );
                 }
-                while ( cursor.next() );
-                cursorMap.remove( id );
+
                 cursor.close();
+                dirty = false;
+            }
+            catch ( LdapException e )
+            {
+                throw e;
+            }
+            catch ( Exception e )
+            {
+                throw new LdapException( e );
             }
         }
     }
@@ -680,12 +370,10 @@ public class SingleFileLdifPartition ext
      * appends all the entries present under a given entry, recursively
      *
      * @param entryId the base entry's id
-     * @param cursorMap the cursor map
-     * @param tmpMovFile a RandomAccessFile to be used as temporary buffer
+     * @param cursorMap the open cursor map
      * @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 ) throws Exception
     {
         synchronized ( lock )
         {
@@ -718,15 +406,10 @@ public class SingleFileLdifPartition ext
                     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" ) );
 
-                    EntryOffset entryOffset = new EntryOffset( childId, pos, tmpMovFile.getFilePointer() );
-                    offsetMap.put( childId, entryOffset );
+                    appendLdif( entry );
 
-                    appendRecursive( childId, cursorMap, tmpMovFile );
+                    appendRecursive( childId, cursorMap );
                 }
                 while ( cursor.next() );
                 cursorMap.remove( entryId );
@@ -737,182 +420,17 @@ public class SingleFileLdifPartition ext
 
 
     /**
-     * inserts a given LDIF entry in the middle of the LDIF entries
-     *
-     * @param entryId the entry's id
-     * @param aboveEntryOffset the immediate top entry's offsets
-     * @param ldif the entry's ldif to be injected
-     * @throws LdapException
-     */
-    private void insertNAppendLdif( Long entryId, EntryOffset aboveEntryOffset, String ldif )
-        throws LdapException
-    {
-        synchronized ( lock )
-        {
-            if ( aboveEntryOffset == null )
-            {
-                throw new IllegalStateException( "parent offset is null" );
-            }
-
-            try
-            {
-                RandomAccessFile tempBufFile = createTempFile();
-                FileChannel tmpBufChannel = tempBufFile.getChannel();
-                FileChannel mainChannel = ldifFile.getChannel();
-
-                long count = ( ldifFile.length() - aboveEntryOffset.getEnd() );
-
-                mainChannel.transferTo( aboveEntryOffset.getEnd(), count, tmpBufChannel );
-                ldifFile.setLength( aboveEntryOffset.getEnd() );
-
-                EntryOffset[] belowParentOffsets = greaterThan( aboveEntryOffset );
-
-                EntryOffset entryOffset = appendLdif( entryId, aboveEntryOffset, ldif );
-
-                long diff = entryOffset.length();
-
-                for ( EntryOffset o : belowParentOffsets )
-                {
-                    o.changeOffsetsBy( diff );
-                }
-
-                tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
-                tmpBufChannel.truncate( 0 );
-            }
-            catch ( IOException e )
-            {
-                throw new LdapException( e );
-            }
-            finally
-            {
-                deleteTempFiles();
-            }
-        }
-    }
-
-
-    /**
-     * replaces an existing entry
-     *
-     * @param entryId the entry's id
-     * @param ldif entry data in LDIF
-     * @throws LdapException
-     */
-    private void replaceLdif( Long entryId, String ldif ) throws LdapException
-    {
-        synchronized ( lock )
-        {
-            try
-            {
-                EntryOffset entryOffset = offsetMap.get( entryId );
-                byte[] utf8Data = StringTools.getBytesUtf8( ldif + "\n" );
-                //long fileLen = ldifFile.length();
-                long diff = utf8Data.length - entryOffset.length();
-
-                /* WARN for some unknown reason the below commented
-                 * optimization block is causing data corruption in
-                 * highly concurrent situations, commenting till we
-                 * understand why!
-                // check if modified entry occupies the same space
-                if ( diff == 0 )
-                {
-                    System.out.println( "RENAME DATA is same ============" );
-                    ldifFile.seek( entryOffset.getStart() );
-                    ldifFile.write( utf8Data );
-                    System.out.print( "" );
-                }
-                else if ( fileLen == entryOffset.getEnd() ) // modified entry is at the end of file
-                {
-                    ldifFile.setLength( entryOffset.getStart() );
-                    ldifFile.write( utf8Data );
-
-                    fileLen = ldifFile.length();
-
-                    // change the offsets, the modified entry size changed
-                    //if ( fileLen != entryOffset.getEnd() )
-                    {
-                        entryOffset = new EntryOffset( entryId, entryOffset.getStart(), ldifFile.getFilePointer() );
-                        offsetMap.put( entryId, entryOffset );
-                    }
-                }
-                else
-                */
-                // modified entry size got changed and is in the middle somewhere
-                {
-                    RandomAccessFile tempBufFile = createTempFile();
-                    FileChannel tmpBufChannel = tempBufFile.getChannel();
-                    FileChannel mainChannel = ldifFile.getChannel();
-
-                    long count = ( ldifFile.length() - entryOffset.getEnd() );
-                    
-                    mainChannel.transferTo( entryOffset.getEnd(), count, tmpBufChannel );
-                    ldifFile.setLength( entryOffset.getStart() );
-
-                    EntryOffset[] belowParentOffsets = greaterThan( entryOffset );
-
-                    entryOffset = appendLdif( entryId, getAboveEntry( entryOffset ), ldif );
-
-                    for ( EntryOffset o : belowParentOffsets )
-                    {
-                        o.changeOffsetsBy( diff );
-                    }
-
-                    tmpBufChannel.transferTo( 0, tmpBufChannel.size(), mainChannel );
-                    tmpBufChannel.truncate( 0 );
-                }
-            }
-            catch ( IOException e )
-            {
-                throw new LdapException( e );
-            }
-            finally
-            {
-                deleteTempFiles();
-            }
-        }
-    }
-
-
-    /**
      * append data to the LDIF file
      *
-     * @param entryId
-     * @param aboveEntryOffset
-     * @param ldif
+     * @param entry the entry to be written
      * @throws LdapException
      */
-    private EntryOffset appendLdif( Long entryId, EntryOffset aboveEntryOffset, String ldif )
-        throws LdapException
+    private void appendLdif( Entry entry ) throws IOException, LdapException
     {
         synchronized ( lock )
         {
-            try
-            {
-                long pos = 0L;
-
-                if ( aboveEntryOffset != null )
-                {
-                    pos = aboveEntryOffset.getEnd();
-                }
-                else
-                {
-                    // erase file
-                    ldifFile.setLength( 0 );
-                }
-
-                ldifFile.seek( pos );
-
-                ldifFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
-
-                EntryOffset entryOffset = new EntryOffset( entryId, pos, ldifFile.getFilePointer() );
-                offsetMap.put( entryId, entryOffset );
-
-                return entryOffset;
-            }
-            catch ( IOException e )
-            {
-                throw new LdapException( e );
-            }
+            String ldif = LdifUtils.convertEntryToLdif( entry );
+            ldifFile.write( StringTools.getBytesUtf8( ldif + "\n" ) );
         }
     }
 
@@ -921,7 +439,6 @@ public class SingleFileLdifPartition ext
      */
     private class RandomAccessLdifReader extends LdifReader
     {
-        private long prevEntryEnd;
         private long len;
 
 
@@ -934,24 +451,10 @@ public class SingleFileLdifPartition ext
             }
             catch ( IOException e )
             {
-                throw new LdapException( e );
-            }
-        }
+                LdapException le = new LdapException( e.getMessage() );
+                le.initCause( e );
 
-
-        @Override
-        protected void readLines() throws LdapLdifException
-        {
-            try
-            {
-                super.readLines();
-                prevEntryEnd = ldifFile.getFilePointer();
-            }
-            catch ( IOException e )
-            {
-                LdapLdifException ldife = new LdapLdifException( e.getMessage() );
-                ldife.initCause( e );
-                throw ldife;
+                throw le;
             }
         }
 
@@ -971,59 +474,6 @@ public class SingleFileLdifPartition ext
 
 
     /**
-     * gets all the EntryOffset objects whose start pos is greater than the given offset mark's start pos 
-     * 
-     * @param mark an EntryOffset object which is considered as a mark
-     * 
-     * @return a sorted set of EntryOffset objects
-     */
-    private EntryOffset[] greaterThan( EntryOffset mark )
-    {
-        synchronized ( lock )
-        {
-
-            Set<EntryOffset> gtSet = new TreeSet<EntryOffset>( comparator );
-
-            for ( EntryOffset o : offsetMap.values() )
-            {
-                if ( o.getStart() > mark.getStart() )
-                {
-                    gtSet.add( o );
-                }
-            }
-
-            EntryOffset[] array = gtSet.toArray( new EntryOffset[0] );
-            Arrays.sort( array, comparator );
-
-            return array;
-        }
-    }
-
-
-    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;
-        }
-    }
-
-
-    /**
      * add the CSN and UUID attributes to the entry if they are not present
      */
     private void addMandatoryOpAt( Entry entry ) throws LdapException
@@ -1041,143 +491,25 @@ public class SingleFileLdifPartition ext
     }
 
 
-    /** a temporary file used for swapping contents while performing update operations */
-    private RandomAccessFile createTempFile() throws IOException
+    @Override
+    protected void doDestroy() throws Exception
     {
-        synchronized ( lock )
-        {
-            File tmpFile = File.createTempFile( "ldifpartition", ".buf" );
-            tmpFile.deleteOnExit();
-
-            RandomAccessFile tempBufFile = new RandomAccessFile( tmpFile.getAbsolutePath(), "rws" );
-            tempBufFile.setLength( 0 );
-
-            tempBufMap.put( tmpFile, tempBufFile );
-            return tempBufFile;
-        }
+        ldifFile.close();
     }
 
-
+    
     /**
-     * clears the temp files used as temporary randomaccess buffers
+     * enable/disable the re-writing of partition data.
+     * This method internally calls the @see {@link #rewritePartitionData()} to save any dirty data if present
+     * 
+     * @param enableRewriting flag to enable/disable re-writing
+     * @throws LdapException
      */
-    private void deleteTempFiles()
-    {
-        synchronized ( lock )
-        {
-            for ( java.util.Map.Entry<File,RandomAccessFile> f : tempBufMap.entrySet() )
-            {
-                try
-                {
-                    f.getValue().close();
-                    f.getKey().delete();
-                }
-                catch( IOException e )
-                {
-                    LOG.warn( "failed to close the random accessfile {}", f.getKey() );
-                }
-            }
-            
-            tempBufMap.clear();
-        }
-    }
-}
-
-
-/**
- * a holder class for containing an entry's start and end offset positions
- * in the LDIF file
- */
-class EntryOffset
-{
-    /** starting position */
-    private long start;
-
-    /** ending position */
-    private long end;
-
-    /** entry id */
-    private Long id;
-
-
-    public EntryOffset( Long id, long start, long end )
-    {
-        this.start = start;
-        this.end = end;
-        this.id = id;
-    }
-
-
-    public long getStart()
-    {
-        return start;
-    }
-
-
-    public long getEnd()
-    {
-        return end;
-    }
-
-
-    public Long getId()
-    {
-        return id;
-    }
-
-
-    public void changeOffsetsBy( long val )
-    {
-        start += val;
-        end += val;
-    }
-
-
-    public long length()
+    public void setEnableRewriting( boolean enableRewriting ) throws LdapException
     {
-        return ( end - start );
-    }
-
-
-    @Override
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ( ( id == null ) ? 0 : id.hashCode() );
-        return result;
-    }
-
-
-    @Override
-    public boolean equals( Object obj )
-    {
-        if ( !( obj instanceof EntryOffset ) )
-        {
-            return false;
-        }
-
-        EntryOffset other = ( EntryOffset ) obj;
+        this.enableRewriting = enableRewriting;
 
-        if ( id == null )
-        {
-            if ( other.id != null )
-            {
-                return false;
-            }
-        }
-        else if ( !id.equals( other.id ) )
-        {
-            return false;
-        }
-
-        return true;
-    }
-
-
-    @Override
-    public String toString()
-    {
-        return "EntryOffset [start=" + start + ", end=" + end + ", id=" + id + "]";
+        // save data if found dirty 
+        rewritePartitionData();
     }
 }

Modified: directory/apacheds/trunk/ldif-partition/src/test/java/org/apache/directory/server/core/partition/SingleFileLdifPartitionTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/ldif-partition/src/test/java/org/apache/directory/server/core/partition/SingleFileLdifPartitionTest.java?rev=1001839&r1=1001838&r2=1001839&view=diff
==============================================================================
--- directory/apacheds/trunk/ldif-partition/src/test/java/org/apache/directory/server/core/partition/SingleFileLdifPartitionTest.java (original)
+++ directory/apacheds/trunk/ldif-partition/src/test/java/org/apache/directory/server/core/partition/SingleFileLdifPartitionTest.java Mon Sep 27 17:54:10 2010
@@ -281,7 +281,7 @@ public class SingleFileLdifPartitionTest
 
         RandomAccessFile file = new RandomAccessFile( partition.getFileName(), "r" );
 
-        assertEquals( getEntryLdifLen( contextEntry ) + 1, file.length() );
+        assertEquals( getEntryLdifLen( contextEntry ), file.length() );
 
         partition = reloadPartition();
         assertExists( partition, contextEntry );
@@ -324,26 +324,6 @@ public class SingleFileLdifPartitionTest
 
         partition.add( addCtx );
 
-        // the below part proves that a child will always get appended
-        // immediately under the parent, not at the end of its siblings
-        // in the LDIF file
-        long ctxEntryLen = getEntryLdifLen( contextEntry );
-        long entry1Len = getEntryLdifLen( entry1 );
-        long len = getEntryLdifLen( entryMvrdn );
-
-        RandomAccessFile file = new RandomAccessFile( partition.getFileName(), "r" );
-
-        file.seek( ctxEntryLen + entry1Len );
-        byte[] data = new byte[( int ) len];
-        file.read( data );
-        String ldif = StringTools.utf8ToString( data );
-
-        LdifEntry fetchedLdif = reader.parseLdif( ldif ).get( 0 );
-
-        Entry fromFetched = new DefaultEntry( schemaManager, fetchedLdif.getEntry() );
-
-        assertEquals( entryMvrdn, fromFetched );
-
         partition = reloadPartition();
         assertExists( partition, contextEntry );
         assertExists( partition, entry1 );
@@ -845,6 +825,41 @@ public class SingleFileLdifPartitionTest
         assertTrue( dc.contains( "child1" ) );
         assertTrue( dc.contains( "movedChild1" ) );
     }
+    
+    
+    @Test
+    public void testEnableRewritingFlag() throws Exception
+    {
+        SingleFileLdifPartition partition = createPartition( null, true );
+        
+        // disable writing
+        partition.setEnableRewriting( false );
+        
+        AddOperationContext addCtx = new AddOperationContext( mockSession );
+        addCtx.setEntry( contextEntry );
+
+        partition.add( addCtx );
+
+        // search works fine
+        Long id = partition.getEntryId( contextEntry.getDn() );
+        assertNotNull( id );
+        assertEquals( contextEntry, partition.lookup( id ) );
+
+        RandomAccessFile file = new RandomAccessFile( partition.getFileName(), "r" );
+
+        // but the file will be empty
+        assertFalse( getEntryLdifLen( contextEntry ) == file.length() );
+
+        partition = reloadPartition();
+        assertNotExists( partition, contextEntry );
+        
+        // try adding on the reloaded partition
+        partition.add( addCtx );
+        
+        // eable writing, this will let the partition write data back to disk
+        partition.setEnableRewriting( false );
+        assertTrue( getEntryLdifLen( contextEntry ) == file.length() );
+    }
 
 
     /**