directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r1195910 - in /directory/apacheds/branches/apacheds-txns: core-api/src/main/java/org/apache/directory/server/core/txn/ core/src/main/java/org/apache/directory/server/core/txn/ core/src/main/java/org/apache/directory/server/core/txn/logedit/...
Date Tue, 01 Nov 2011 10:01:54 GMT
Author: saya
Date: Tue Nov  1 10:01:54 2011
New Revision: 1195910

URL: http://svn.apache.org/viewvc?rev=1195910&view=rev
Log:
Test for index cursor wrapper and fixes based on it. Also logging index changes for a txn is tested.

Added:
    directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/IndexCursorWrapperTest.java
Modified:
    directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnManager.java
    directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/IndexCursorWrapper.java
    directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadWriteTxn.java
    directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/DataChangeContainer.java
    directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/IndexChange.java
    directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/DefaultTxnManagerTest.java
    directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/TxnIndexCursorTest.java

Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnManager.java?rev=1195910&r1=1195909&r2=1195910&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnManager.java (original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnManager.java Tue Nov  1 10:01:54 2011
@@ -29,13 +29,43 @@ import java.util.Comparator;
  */
 public interface TxnManager<ID>
 {
+    /**
+     * Starts a new txn and associates it with the current thread.
+     *
+     * @param readOnly whether the txn is read only
+     * @throws IOException
+     */
     void beginTransaction( boolean readOnly ) throws IOException;
    
+    /**
+     * Tries to commit the current txn associated with the current thread. ReadWrite txns have to be verified against txns
+     * that committed after they started for any conflicting change and conflicting
+     * exception is thrown if verificatin fails.
+     *
+     * @throws IOException
+     * @throws TxnConflictException
+     */
     void commitTransaction() throws IOException, TxnConflictException;
     
+    /**
+     * Aborts the current txn associated with the current thread.
+     *
+     * @throws IOException
+     */
     void abortTransaction() throws IOException;
     
+    /**
+     * Returns the id comparator used by the txn manager. 
+     *
+     * @return id comparator
+     */
     Comparator<ID> getIDComparator();
     
+    
+    /**
+     * Returns the id serializer used by the txn manager.
+     *
+     * @return id serializer 
+     */
     Serializer getIDSerializer();
 }

Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/IndexCursorWrapper.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/IndexCursorWrapper.java?rev=1195910&r1=1195909&r2=1195910&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/IndexCursorWrapper.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/IndexCursorWrapper.java Tue Nov  1 10:01:54 2011
@@ -33,6 +33,19 @@ import org.apache.directory.shared.ldap.
 import org.apache.directory.shared.ldap.model.entry.Entry;;
 
 /**
+ * Wraps an index's cursor and provides a transactionally consistent view.
+ * 
+ * Each transaction that this txn depends exposes a TxnIndexCursor if it
+ * has adds for the wrapped cursor's index. This cursor wraps them as well. 
+ * Whenever the cursor is positioned, all wrapped cursors are positioned and
+ * available values for each cursor is reset to null. Whenever a next or 
+ * previous call is made:
+ *  *If the call is after a positioning call, we do a next or prev on all wrapped
+ *  cursors
+ *  * Otherwise we do a next or prev on the last cursor we go the value from.
+ *  
+ *  After the above step, we recompute the minimum. The new index is the value 
+ *  we will get the value from.
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
@@ -83,7 +96,9 @@ public class IndexCursorWrapper<ID> exte
         List<ReadWriteTxn<ID>> toCheck = curTxn.getTxnsToCheck(); 
         
         cursors = new ArrayList<IndexCursor<Object, Entry, ID>>( toCheck.size() + 1 );
+        values = new ArrayList<IndexEntry<Object,ID>>( toCheck.size() + 1 );
         cursors.add( ( IndexCursor<Object, Entry, ID> )wrappedCursor );
+        values.add( null );
         
         if ( toCheck.size() > 0 )
         {
@@ -104,6 +119,9 @@ public class IndexCursorWrapper<ID> exte
                     txns.add( null );
                 }
                 
+                values.add( null );
+                
+                // This adds a null to the array if the txn does not have any changes for the index
                 cursors.add( dependentTxn.getCursorFor( partitionDn, attributeOid, forwardIndex, onlyValueKey, onlyIDKey, comparator ) );
             }
         }
@@ -129,7 +147,7 @@ public class IndexCursorWrapper<ID> exte
             
             if ( cursor != null )
             {
-             cursor.after( element );
+                cursor.after( element );
             }
         }
         
@@ -319,10 +337,15 @@ public class IndexCursorWrapper<ID> exte
             beforeFirst();
         }
         
+        /*
+         *  If called right after positioning the cursor or changing direction, then do a next call
+         *  on every wrapped cursor and recompute the min value.
+         */
         if ((  movingNext == false ) || ( getIndex < 0 ) )
         {
             minValue = null;
             getIndex = -1;
+            movingNext = true;
             
             for ( idx = 0; idx < values.size(); idx++ )
             {
@@ -378,14 +401,14 @@ public class IndexCursorWrapper<ID> exte
             {
                 curTxn = txns.get( txnIdx );
                 
-                // TODO check for index entry delete here
-                if ( curTxn!= null)
+                if ( ( curTxn != null ) && ( curTxn.isIndexEntryDeleted( partitionDn, attributeOid, value ) ) )
                 {
                     valueDeleted = true;
                     break;
                 }
             }
             
+            // If the value we get is not deleted and greater than the last value we returned, then we are done
             if ( ( valueDeleted == false ) && ( ( lastValue == null ) || ( comparator.compare( value, lastValue ) > 0 ) ) )
             {
                 break;
@@ -425,16 +448,22 @@ public class IndexCursorWrapper<ID> exte
             afterLast();
         }
         
-        if ( ( movingNext == false ) || ( getIndex < 0 ) )
+        
+        /*
+         *  If called right after positioning the cursor or changing direction, then do a previous call
+         *  on every wrapped cursor and recompute the max value.
+         */
+        if ( ( movingNext == true ) || ( getIndex < 0 ) )
         {
             maxValue = null;
             getIndex = -1;
+            movingNext = false;
             
             for ( idx = 0; idx < values.size(); idx++ )
             {
                 cursor = cursors.get( idx );
                 
-                if ( ( cursor != null ) && cursor.next() )
+                if ( ( cursor != null ) && cursor.previous() )
                 {
                     value = cursor.get();
                     
@@ -484,14 +513,14 @@ public class IndexCursorWrapper<ID> exte
             {
                 curTxn = txns.get( txnIdx );
                 
-                // TODO check for index entry delete here
-                if ( curTxn!= null)
+                if ( curTxn!= null && curTxn.isIndexEntryDeleted( partitionDn, attributeOid, value ) )
                 {
                     valueDeleted = true;
                     break;
                 }
             }
             
+            // If the value we get is not deleted and less than the last value we returned, then we are done
             if ( ( valueDeleted == false ) && ( ( lastValue == null ) || ( comparator.compare( value, lastValue ) < 0 ) ) )
             {
                 break;
@@ -499,6 +528,7 @@ public class IndexCursorWrapper<ID> exte
             
             // Recompute maximum
             recomputeMaximum();
+            
         } while ( true );
         
         return ( getIndex >= 0 );
@@ -583,6 +613,11 @@ public class IndexCursorWrapper<ID> exte
     }
 
     
+    /**
+     * Do a get on the last cursor we got the value from and recompute the minimum
+     *
+     * @throws Exception
+     */
     private void recomputeMinimum() throws Exception
     {
         IndexCursor<Object,Entry,ID> cursor;
@@ -620,7 +655,11 @@ public class IndexCursorWrapper<ID> exte
         }
     }
     
-    
+    /**
+     * Do a previous we got the value from and recompute the maximum.
+     *
+     * @throws Exception
+     */
     private void recomputeMaximum() throws Exception
     {
         IndexCursor<Object,Entry,ID> cursor;
@@ -630,7 +669,7 @@ public class IndexCursorWrapper<ID> exte
         
         cursor = cursors.get( getIndex );
         
-        if ( cursor.next() )
+        if ( cursor.previous() )
         {
             values.set( getIndex , cursor.get() );
         }

Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadWriteTxn.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadWriteTxn.java?rev=1195910&r1=1195909&r2=1195910&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadWriteTxn.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadWriteTxn.java Tue Nov  1 10:01:54 2011
@@ -39,6 +39,7 @@ import org.apache.directory.server.core.
 import org.apache.directory.server.core.log.UserLogRecord;
 
 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;
@@ -113,109 +114,138 @@ import org.apache.directory.shared.ldap.
     }
     
     
+    
+    /**
+     * Logs the given log edit for this txn. If the edit contains index changes, it updates the summary
+     * of changes for the changed index so that it is easier to provide a cursor view over the set of 
+     * index changes.
+     *
+     * @param edit txn log edit to be logged
+     */
     @SuppressWarnings("unchecked")
     public void addLogEdit( LogEdit<ID> edit )
     {
         logEdits.add( edit );
-        
+
         /*
          * Update the in memory summary of the index changes
          */
         if ( edit instanceof DataChangeContainer )
         {
-            DataChangeContainer<ID> dEdit = (DataChangeContainer<ID>)edit; 
-            List<DataChange<ID>> dataChanges =  dEdit.getChanges();
+            DataChangeContainer<ID> dEdit = ( DataChangeContainer<ID> ) edit;
+            List<DataChange<ID>> dataChanges = dEdit.getChanges();
             Iterator<DataChange<ID>> it = dataChanges.iterator();
             Dn partitionDn = dEdit.getPartitionDn();
-            
+
             DataChange<ID> nextChange;
             IndexChange<ID> indexChange;
             IndexChange.Type indexChangeType;
-            ForwardIndexEntry<Object,ID> indexEntry;
-            
-            Map<String, TreeSet<IndexEntry<Object,ID>>> forwardIndices = 
+            ForwardIndexEntry<Object, ID> indexEntry;
+            ReverseIndexEntry<Object, ID> reverseIndexEntry;
+
+            Map<String, TreeSet<IndexEntry<Object, ID>>> forwardIndices =
                 forwardIndexAdds.get( partitionDn );
-            
-            Map<String, TreeSet<IndexEntry<Object,ID>>> reverseIndices = 
+
+            Map<String, TreeSet<IndexEntry<Object, ID>>> reverseIndices =
                 reverseIndexAdds.get( partitionDn );
-            
+
             if ( forwardIndices == null )
             {
-                forwardIndices = new HashMap<String, TreeSet<IndexEntry<Object,ID>>>();
-                
+                forwardIndices = new HashMap<String, TreeSet<IndexEntry<Object, ID>>>();
+
                 // Reverse index changes should be null too
-                reverseIndices = new HashMap<String, TreeSet<IndexEntry<Object,ID>>>();
-                
+                if ( reverseIndices != null )
+                {
+                    throw new IllegalStateException(
+                        "Reverse Index changes for partition are not null while forward index changes are null"
+                            + partitionDn );
+                }
+
+                reverseIndices = new HashMap<String, TreeSet<IndexEntry<Object, ID>>>();
+
                 forwardIndexAdds.put( partitionDn, forwardIndices );
                 reverseIndexAdds.put( partitionDn, reverseIndices );
             }
-            
-            Map<String, TreeSet< IndexEntry<Object,ID>>> deletedIndices = 
-                    indexDeletes.get( partitionDn ); 
-            
+
+            Map<String, TreeSet<IndexEntry<Object, ID>>> deletedIndices =
+                indexDeletes.get( partitionDn );
+
             if ( deletedIndices == null )
             {
-                deletedIndices = new HashMap<String, TreeSet< IndexEntry<Object,ID>>>();
+                deletedIndices = new HashMap<String, TreeSet<IndexEntry<Object, ID>>>();
                 indexDeletes.put( partitionDn, deletedIndices );
             }
-            
+
             while ( it.hasNext() )
             {
                 nextChange = it.next();
-                
+
                 if ( nextChange instanceof IndexChange )
                 {
-                    indexChange = (IndexChange<ID>) nextChange;
+                    indexChange = ( IndexChange<ID> ) nextChange;
                     indexChangeType = indexChange.getType();
-                    Index<Object,?,ID> index = (Index<Object,?,ID>)indexChange.getIndex();
-                    
-                    TreeSet<IndexEntry<Object,ID>> forwardAdds = 
+                    Index<Object, ?, ID> index = ( Index<Object, ?, ID> ) indexChange.getIndex();
+
+                    TreeSet<IndexEntry<Object, ID>> forwardAdds =
                         forwardIndices.get( indexChange.getOID() );
-                    
-                    TreeSet<IndexEntry<Object,ID>> reverseAdds = 
+
+                    TreeSet<IndexEntry<Object, ID>> reverseAdds =
                         reverseIndices.get( indexChange.getOID() );
-                    
+
                     if ( forwardAdds == null )
                     {
-                        forwardAdds = 
+                        forwardAdds =
                             new TreeSet<IndexEntry<Object, ID>>( index.getForwardIndexEntryComparator() );
-                        reverseAdds = 
+
+                        // Reverse index changes should be null too
+                        if ( reverseAdds != null )
+                        {
+                            throw new IllegalStateException(
+                                "Reverse Index changes for partition are not null while forward index changes are null"
+                                    + partitionDn + indexChange.getOID() );
+                        }
+
+                        reverseAdds =
                             new TreeSet<IndexEntry<Object, ID>>( index.getReverseIndexEntryComparator() );
-                        
+
                         forwardIndices.put( indexChange.getOID(), forwardAdds );
                         reverseIndices.put( indexChange.getOID(), forwardAdds );
                     }
-                    
-                    TreeSet<IndexEntry<Object,ID>> deletes = deletedIndices.get( indexChange.getOID() );
-                    
+
+                    TreeSet<IndexEntry<Object, ID>> deletes = deletedIndices.get( indexChange.getOID() );
+
                     if ( deletes == null )
                     {
-                        deletes = new TreeSet<IndexEntry<Object,ID>>( index.getForwardIndexEntryComparator() );
+                        deletes = new TreeSet<IndexEntry<Object, ID>>( index.getForwardIndexEntryComparator() );
                         deletedIndices.put( indexChange.getOID(), deletes );
                     }
-                    
-                    indexEntry = new ForwardIndexEntry<Object,ID>();
+
+                    indexEntry = new ForwardIndexEntry<Object, ID>();
                     indexEntry.setValue( indexChange.getKey() );
                     indexEntry.setId( indexChange.getID() );
-                    
+
+                    reverseIndexEntry = new ReverseIndexEntry<Object, ID>();
+                    reverseIndexEntry.setValue( indexChange.getKey() );
+                    reverseIndexEntry.setId( indexChange.getID() );
+
                     if ( indexChangeType == IndexChange.Type.ADD )
                     {
                         deletes.remove( indexEntry );
                         forwardAdds.add( indexEntry );
-                        reverseAdds.add( indexEntry );
+                        reverseAdds.add( reverseIndexEntry );
                     }
                     else
                     {
                         deletes.add( indexEntry );
                         forwardAdds.remove( indexEntry );
-                        reverseAdds.remove( indexEntry );
+                        reverseAdds.remove( reverseIndexEntry );
                     }
                 }
             }
-        } 
+        }
     }
-    
-    
+
+
     public Entry applyUpdatesToEntry( Dn partitionDn, ID entryID, Entry curEntry, boolean cloneOnChange )
     {
         boolean needToCloneOnChange = cloneOnChange;
@@ -329,83 +359,137 @@ import org.apache.directory.shared.ldap.
         return curEntry;
     }
     
-    
+
+    /**
+     * Returns true if this txn has deletes for the index identified by partitionDn + attributeOid
+     *
+     * @param partitionDn dn of the partition
+     * @param attributeOid oid of the indexed attribute
+     * @return
+     */
     public boolean hasDeletesFor( Dn partitionDn, String attributeOid )
     {
-        Map<String, TreeSet< IndexEntry<Object,ID>>> deletedIndices = 
-            indexDeletes.get( partitionDn ); 
-        
+        Map<String, TreeSet<IndexEntry<Object, ID>>> deletedIndices =
+            indexDeletes.get( partitionDn );
+
         if ( deletedIndices != null )
         {
             return ( deletedIndices.get( attributeOid ) != null );
         }
-       
+
         return false;
     }
-    
-    
-    public IndexCursor<Object,Entry,ID> getCursorFor( Dn partitionDn, String attributeOid, boolean forwardIndex, Object onlyValueKey, ID onlyIDKey, IndexComparator<Object,ID> comparator )
+
+
+    /**
+     * Returns a cursor over the changes made by this txn on the index identified by partitionDn+attributeOid. 
+     *
+     * @param partitionDn dn of the partition
+     * @param attributeOid oid of the indexed attribute
+     * @param forwardIndex true if forward index and reverse if reverse index
+     * @param onlyValueKey set if the cursor should be locked down by a key ( should be non null only for forward indices )
+     * @param onlyIDKey  set if the cursor should be locked down by a key ( should be non null only for reverse indices )
+     * @param comparator comparator that will be used to order index entries.
+     * @return
+     */
+    public IndexCursor<Object, Entry, ID> getCursorFor( Dn partitionDn, String attributeOid, boolean forwardIndex,
+        Object onlyValueKey, ID onlyIDKey, IndexComparator<Object, ID> comparator )
     {
         TxnIndexCursor<ID> txnIndexCursor = null;
-        
-        Map<String, TreeSet<IndexEntry<Object,ID>>> forwardIndices = 
+
+        Map<String, TreeSet<IndexEntry<Object, ID>>> forwardIndices =
             forwardIndexAdds.get( partitionDn );
-        
+
         if ( forwardIndices != null )
         {
             TreeSet<IndexEntry<Object, ID>> sortedSet = forwardIndices.get( attributeOid );
-            
+
             if ( sortedSet != null )
             {
                 txnIndexCursor = new TxnIndexCursor<ID>( sortedSet, forwardIndex, onlyValueKey, onlyIDKey, comparator );
             }
         }
-        
+
         return txnIndexCursor;
     }
-    
+
+
+    /**
+     * Returns true if the given index entry is deleted by this txn. partitionDn + attributeOid 
+     * identifies the index. 
+     *
+     * @param partitionDn dn of the partition index belongs to 
+     * @param attributeOid oid of the indexed attribute.
+     * @param indexEntry value to be checked
+     * @return true if the given value is deleted.
+     */
+    public boolean isIndexEntryDeleted( Dn partitionDn, String attributeOid, IndexEntry<Object, ID> indexEntry )
+    {
+        Map<String, TreeSet<IndexEntry<Object, ID>>> deletedIndices =
+            indexDeletes.get( partitionDn );
+
+        if ( deletedIndices == null )
+        {
+            return false;
+        }
+
+        TreeSet<IndexEntry<Object, ID>> deletedEntries = deletedIndices.get( attributeOid );
+
+        if ( deletedEntries == null )
+        {
+            return false;
+        }
+
+        boolean result = deletedEntries.contains( indexEntry );
+
+        return result;
+    }
+
+
     public void addRead( DnSet readSet )
     {
         readDns.add( readSet );
     }
-    
+
+
     public void addWrite( DnSet writeSet )
     {
         writeDns.add( writeSet );
-        
+
         // Changing a dn means also read dependency
         readDns.add( writeSet );
     }
-    
+
+
     public List<DnSet> getWriteSet()
     {
         return writeDns;
     }
-    
+
+
     public boolean hasConflict( ReadWriteTxn txn )
     {
         boolean result = false;
-        
-        
+
         List<DnSet> txnWriteDns = txn.getWriteSet();
         Iterator<DnSet> writeIt = txnWriteDns.iterator();
         Iterator<DnSet> readIt = readDns.iterator();
-        
+
         DnSet readDnSet;
         SearchScope readScope;
         DnSet writeDnSet;
         SearchScope writeScope;
-        
+
         while ( readIt.hasNext() )
         {
-            readDnSet =  readIt.next();
+            readDnSet = readIt.next();
             readScope = readDnSet.getScope();
-            
+
             while ( writeIt.hasNext() )
             {
                 writeDnSet = writeIt.next();
                 writeScope = writeDnSet.getScope();
-                
+
                 if ( readScope.equals( SearchScope.OBJECT ) )
                 {
                     if ( writeScope.equals( SearchScope.OBJECT ) )
@@ -416,7 +500,8 @@ import org.apache.directory.shared.ldap.
                             break;
                         }
                     }
-                    else //one level or subtree scope for the write.
+                    else
+                    //one level or subtree scope for the write.
                     {
                         // Even if one level scope, conservatively check the whole subtree
                         if ( readDnSet.getBaseDn().isDescendantOf( writeDnSet.getBaseDn() ) )
@@ -426,7 +511,8 @@ import org.apache.directory.shared.ldap.
                         }
                     }
                 }
-                else //one level or subtree scope for the read.
+                else
+                //one level or subtree scope for the read.
                 {
                     if ( writeScope.equals( SearchScope.OBJECT ) )
                     {
@@ -436,11 +522,12 @@ import org.apache.directory.shared.ldap.
                             break;
                         }
                     }
-                    else //one level or subtree scope for the write.
+                    else
+                    //one level or subtree scope for the write.
                     {
                         // Even if one level scope, conservatively check if any basedn is descendent of the other
-                        if ( ( readDnSet.getBaseDn().isDescendantOf( writeDnSet.getBaseDn() ) ) || 
-                              ( readDnSet.getBaseDn().isAncestorOf( writeDnSet.getBaseDn() ) )  )
+                        if ( ( readDnSet.getBaseDn().isDescendantOf( writeDnSet.getBaseDn() ) ) ||
+                            ( readDnSet.getBaseDn().isAncestorOf( writeDnSet.getBaseDn() ) ) )
                         {
                             result = true;
                             break;
@@ -449,7 +536,7 @@ import org.apache.directory.shared.ldap.
                 }
             } // end of inner while loop
         } // end of outer while loop
-        
+
         return result;
     }
 }

Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/DataChangeContainer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/DataChangeContainer.java?rev=1195910&r1=1195909&r2=1195910&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/DataChangeContainer.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/DataChangeContainer.java Tue Nov  1 10:01:54 2011
@@ -19,6 +19,7 @@
  */
 package org.apache.directory.server.core.txn.logedit;
 
+
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
@@ -33,89 +34,105 @@ import org.apache.directory.server.core.
 
 import org.apache.directory.server.core.txn.TxnManagerFactory;
 
+
 /**
- * 
+ * A container for index and entry changes. If any entry change is contained, then they are for a single entry.All changes 
+ * contained for an entry belong to a single version and can be atomically applied to the entry in question.
+ *  
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public class DataChangeContainer<ID> extends AbstractLogEdit<ID>
 {
     /** Set to the uuid of the entry if the container contains a change for the entry, null otherwise */
     private String uuid;
-    
+
     /** id of the entry if the container contains a change for an entry */
     private ID entryID;
-    
+
     /** Transaction under which the change is done */
     private long txnID;
-    
+
     /** partition this change applies to */
     private Dn partitionDn;
-    
+
     /** List of data changes */
     private List<DataChange<ID>> changes = new LinkedList<DataChange<ID>>();
-    
+
+
     //For externalizable
     public DataChangeContainer()
     {
-        
+
     }
-    
-    public DataChangeContainer( Dn partitionDn, long txnID)
+
+
+    public DataChangeContainer( Dn partitionDn )
     {
         this.partitionDn = partitionDn;
-        this.txnID = txnID;
     }
-    
-    
+
+
     public String getUUID()
     {
         return uuid;
     }
-    
-    
+
+
     public void setUUID( String entryUUID )
     {
         this.uuid = entryUUID;
     }
-    
-    
+
+
     public long getTxnID()
     {
         return txnID;
     }
-    
-    
+
+
+    public void setTxnID( long id )
+    {
+        txnID = id;
+    }
+
+
     public Dn getPartitionDn()
     {
         return partitionDn;
     }
-    
-    
+
+
     public ID getEntryID()
     {
         return entryID;
     }
-    
-    
+
+
+    public void setEntryID( ID id )
+    {
+        entryID = id;
+    }
+
+
     public List<DataChange<ID>> getChanges()
     {
         return changes;
     }
-    
-    
+
+
     @Override
     public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
     {
         Serializer idSerializer = TxnManagerFactory.txnManagerInstance().getIDSerializer();
         boolean uuidNotNull = in.readBoolean();
-        
+
         if ( uuidNotNull )
         {
             uuid = in.readUTF();
         }
-        
-        int len = in.readInt(); 
-        
+
+        int len = in.readInt();
+
         if ( len < 0 )
         {
             entryID = null;
@@ -124,20 +141,20 @@ public class DataChangeContainer<ID> ext
         {
             byte[] buf = new byte[len];
             in.readFully( buf );
-            entryID = (ID)idSerializer.deserialize( buf );
+            entryID = ( ID ) idSerializer.deserialize( buf );
         }
-        
+
         txnID = in.readLong();
-        
+
         partitionDn = new Dn();
         partitionDn.readExternal( in );
-        
+
         DataChange<ID> change;
         int numChanges = in.readInt();
-        
+
         for ( int idx = 0; idx < numChanges; idx++ )
         {
-            change = (DataChange<ID>)in.readObject();
+            change = ( DataChange<ID> ) in.readObject();
             changes.add( change );
         }
     }
@@ -148,7 +165,7 @@ public class DataChangeContainer<ID> ext
     {
         Serializer idSerializer = TxnManagerFactory.txnManagerInstance().getIDSerializer();
         DataChange<ID> change;
-        
+
         if ( uuid != null )
         {
             out.writeBoolean( true );
@@ -158,7 +175,7 @@ public class DataChangeContainer<ID> ext
         {
             out.writeBoolean( false );
         }
-        
+
         if ( entryID == null )
         {
             out.writeInt( -1 );
@@ -169,16 +186,16 @@ public class DataChangeContainer<ID> ext
             out.writeInt( buf.length );
             out.write( buf );
         }
-        
+
         out.writeLong( txnID );
-        
+
         partitionDn.writeExternal( out );
-        
+
         out.writeInt( changes.size() );
-        
+
         Iterator<DataChange<ID>> it = changes.iterator();
-        
-        while( it.hasNext() )
+
+        while ( it.hasNext() )
         {
             change = it.next();
             change.writeExternal( out );

Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/IndexChange.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/IndexChange.java?rev=1195910&r1=1195909&r2=1195910&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/IndexChange.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/IndexChange.java Tue Nov  1 10:01:54 2011
@@ -19,6 +19,7 @@
  */
 package org.apache.directory.server.core.txn.logedit;
 
+
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
@@ -29,6 +30,7 @@ import org.apache.directory.server.core.
 
 import org.apache.directory.shared.ldap.model.entry.Value;
 
+
 /**
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
@@ -37,25 +39,27 @@ public class IndexChange<ID> extends Abs
 {
     /** Index this change is done on */
     private transient Index<?, ?, ID> index;
-    
+
     /** oid of the attribute the index is on */
     private String oid;
-    
+
     /** key of the forward index */
-    private Value<?> key;
-    
+    private Object key;
+
     /** if for the index */
     private ID id;
-    
+
     /** Change type */
     Type type;
-    
+
+
     // For externalizable
     public IndexChange()
     {
     }
-    
-    public IndexChange( Index<?, ?, ID> index, String oid, Value<?> key, ID id, Type type )
+
+
+    public IndexChange( Index<?, ?, ID> index, String oid, Object key, ID id, Type type )
     {
         this.index = index;
         this.oid = oid;
@@ -63,52 +67,52 @@ public class IndexChange<ID> extends Abs
         this.id = id;
         this.type = type;
     }
-    
-    
+
+
     public String getOID()
     {
         return oid;
     }
-    
-    
+
+
     public Index<?, ?, ID> getIndex()
     {
         return index;
     }
-    
-    
-    public Value<?> getKey()
+
+
+    public Object getKey()
     {
         return key;
     }
-    
-    
+
+
     public ID getID()
     {
         return id;
     }
-    
-    
+
+
     public Type getType()
     {
         return type;
     }
-    
-    
+
+
     @Override
     @SuppressWarnings("unchecked")
     public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
     {
         Serializer idSerializer = TxnManagerFactory.txnManagerInstance().getIDSerializer();
-        
+
         oid = in.readUTF();
-        key = (Value<?>) in.readObject();
-        
+        key = ( Value<?> ) in.readObject();
+
         int len = in.readInt();
         byte[] buf = new byte[len];
         in.readFully( buf );
-        id = (ID)idSerializer.deserialize( buf );
-        
+        id = ( ID ) idSerializer.deserialize( buf );
+
         type = Type.values()[in.readInt()];
     }
 
@@ -117,18 +121,17 @@ public class IndexChange<ID> extends Abs
     public void writeExternal( ObjectOutput out ) throws IOException
     {
         Serializer idSerializer = TxnManagerFactory.txnManagerInstance().getIDSerializer();
-        
+
         out.writeUTF( oid );
         out.writeObject( key );
-        
+
         byte[] buf = idSerializer.serialize( id );
         out.writeInt( buf.length );
         out.write( buf );
-        
+
         out.writeInt( type.ordinal() );
     }
-    
-    
+
     public enum Type
     {
         ADD,

Modified: directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/DefaultTxnManagerTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/DefaultTxnManagerTest.java?rev=1195910&r1=1195909&r2=1195910&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/DefaultTxnManagerTest.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/DefaultTxnManagerTest.java Tue Nov  1 10:01:54 2011
@@ -1,7 +1,9 @@
 
 package org.apache.directory.server.core.txn;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.ObjectOutputStream;
 
 import org.apache.directory.server.core.log.InvalidLogException;
 import org.junit.After;
@@ -46,11 +48,19 @@ public class DefaultTxnManagerTest
 
 
     @Before
-    public void setup() throws IOException, InvalidLogException
+    public void setup()
     {
-        TxnManagerFactory.<Long> init( LongComparator.INSTANCE, LongSerializer.INSTANCE, getLogFolder(), logBufferSize,
-            logFileSize );
-        txnManager = TxnManagerFactory.<Long> txnManagerInternalInstance();
+        try
+        {
+            TxnManagerFactory.<Long> init( LongComparator.INSTANCE, LongSerializer.INSTANCE, getLogFolder(),
+                logBufferSize, logFileSize );
+            txnManager = TxnManagerFactory.<Long> txnManagerInternalInstance();
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+            fail();
+        }
     }
 
 
@@ -61,7 +71,7 @@ public class DefaultTxnManagerTest
 
 
     @Test
-    public void testBeginCommitReadOnlyTxn()
+    public void testBeginCommitReadOnlyTxn() throws IOException
     {
         try
         {

Added: directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/IndexCursorWrapperTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/IndexCursorWrapperTest.java?rev=1195910&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/IndexCursorWrapperTest.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/IndexCursorWrapperTest.java Tue Nov  1 10:01:54 2011
@@ -0,0 +1,383 @@
+package org.apache.directory.server.core.txn;
+
+
+import java.io.IOException;
+import java.util.TreeSet;
+
+import org.apache.directory.server.core.api.partition.index.ForwardIndexComparator;
+import org.apache.directory.server.core.api.partition.index.ForwardIndexEntry;
+import org.apache.directory.server.core.api.partition.index.IndexEntry;
+import org.apache.directory.server.core.api.partition.index.GenericIndex;
+import org.apache.directory.server.core.api.partition.index.ReverseIndexComparator;
+import org.apache.directory.server.core.api.partition.index.IndexCursor;
+
+import org.apache.directory.server.core.log.InvalidLogException;
+
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+import org.junit.Test;
+
+import org.apache.directory.server.core.txn.logedit.IndexChange;
+import org.apache.directory.server.core.txn.logedit.DataChangeContainer;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+public class IndexCursorWrapperTest
+{
+    /** Test partition Dn */
+    private Dn dn;
+
+    /** Mock attribute oid */
+    private String attributeOid = "mockOid";
+
+    /** Mock index with the mock attributeoid */
+    private MockIndex mockIndex = new MockIndex();
+
+    /** Log buffer size : 4096 bytes */
+    private int logBufferSize = 1 << 12;
+
+    /** Log File Size : 8192 bytes */
+    private long logFileSize = 1 << 13;
+
+    /** log suffix */
+    private static String LOG_SUFFIX = "log";
+
+    /** Txn manager */
+    private TxnManagerInternal<Long> txnManager;
+
+    /** Txn log manager */
+    private TxnLogManager<Long> txnLogManager;
+
+    /** index entry comparator */
+    private ForwardIndexComparator<?, Long> comparator = new ForwardIndexComparator<Long, Long>(
+        LongComparator.INSTANCE,
+        LongComparator.INSTANCE );
+
+    /** sorted change set for the cursor */
+    private TreeSet<IndexEntry<Object, Long>> changedSet;
+
+    /** Cursor to be wrapped*/
+    private TxnIndexCursor<Long> cursor;
+
+    /** Cursor wrapper */
+    private IndexCursor<Object, Entry, Long> cursorWrapper;
+
+    @Rule
+    public TemporaryFolder folder = new TemporaryFolder();
+
+
+    /**
+     * Get the Log folder
+     */
+    private String getLogFolder() throws IOException
+    {
+        String file = folder.newFolder( LOG_SUFFIX ).getAbsolutePath();
+
+        return file;
+    }
+
+
+    @Before
+    @SuppressWarnings("unchecked")
+    public void setup() throws IOException, InvalidLogException
+    {
+        try
+        {
+            // Init the test dn
+            dn = new Dn( "cn=Test", "ou=department" );
+
+            // Init the txn manager
+            TxnManagerFactory.<Long> init( LongComparator.INSTANCE, LongSerializer.INSTANCE, getLogFolder(),
+                logBufferSize, logFileSize );
+            txnManager = TxnManagerFactory.<Long> txnManagerInternalInstance();
+            txnLogManager = TxnManagerFactory.<Long> txnLogManagerInstance();
+
+            // Prepare the to be wrapped cursor
+            ForwardIndexEntry<Object, Long> idxEntry;
+            changedSet = new TreeSet<IndexEntry<Object, Long>>( ( ForwardIndexComparator<Object, Long> ) comparator );
+
+            for ( int idx = 0; idx < 10; idx++ )
+            {
+                if ( idx != 5 )
+                {
+                    idxEntry = new ForwardIndexEntry<Object, Long>();
+                    idxEntry.setValue( new Long( idx ) );
+                    idxEntry.setId( new Long( idx ) );
+                    changedSet.add( idxEntry );
+                }
+
+                if ( idx != 5 && idx != 0 )
+                {
+                    idxEntry = new ForwardIndexEntry<Object, Long>();
+                    idxEntry.setValue( new Long( idx ) );
+                    idxEntry.setId( new Long( idx + 1 ) );
+                    changedSet.add( idxEntry );
+                }
+            }
+
+            cursor = new TxnIndexCursor<Long>( changedSet, true, null, null, comparator );
+
+            IndexChange<Long> idxChange;
+
+            // Begin a txn and do some index changes.
+            DataChangeContainer<Long> changeContainer = new DataChangeContainer<Long>( dn );
+            txnManager.beginTransaction( false );
+
+            // Add (5,5) missing in the original index 
+            idxChange = new IndexChange<Long>( mockIndex, attributeOid, new Long( 5 ), new Long( 5 ),
+                IndexChange.Type.ADD );
+            changeContainer.getChanges().add( idxChange );
+
+            // Add (10,11) missing in the original index 
+            idxChange = new IndexChange<Long>( mockIndex, attributeOid, new Long( 10 ), new Long( 11 ),
+                IndexChange.Type.ADD );
+            changeContainer.getChanges().add( idxChange );
+
+            // Delete (6,6) existing in the original index 
+            idxChange = new IndexChange<Long>( mockIndex, attributeOid, new Long( 6 ), new Long( 6 ),
+                IndexChange.Type.DELETE );
+            changeContainer.getChanges().add( idxChange );
+
+            // add the log edit to the current txn
+            txnLogManager.log( changeContainer, false );
+
+            txnManager.commitTransaction();
+
+            // Begin another txn and do some more index changes
+            changeContainer = new DataChangeContainer<Long>( dn );
+            txnManager.beginTransaction( false );
+
+            // Add (4,5) already existing in the original index 
+            idxChange = new IndexChange<Long>( mockIndex, attributeOid, new Long( 4 ), new Long( 5 ),
+                IndexChange.Type.ADD );
+            changeContainer.getChanges().add( idxChange );
+
+            // Re add (0,1) missing in the original index 
+            idxChange = new IndexChange<Long>( mockIndex, attributeOid, new Long( 0 ), new Long( 1 ),
+                IndexChange.Type.ADD );
+            changeContainer.getChanges().add( idxChange );
+
+            // Delete (10,11) added by the previous txn 
+            idxChange = new IndexChange<Long>( mockIndex, attributeOid, new Long( 10 ), new Long( 11 ),
+                IndexChange.Type.DELETE );
+            changeContainer.getChanges().add( idxChange );
+
+            txnLogManager.log( changeContainer, false );
+
+            txnManager.commitTransaction();
+
+            // Begin a read only txn and prepare the cursor wrapper 
+            txnManager.beginTransaction( true );
+
+            cursorWrapper = txnLogManager.wrap( dn, cursor, ( ForwardIndexComparator<Object, Long> ) comparator,
+                attributeOid, true, null, null );
+
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail();
+        }
+
+    }
+
+
+    @After
+    public void teardown() throws IOException
+    {
+        try
+        {
+            txnManager.commitTransaction();
+
+            if ( cursorWrapper != null )
+            {
+                cursorWrapper.close();
+            }
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testAfter()
+    {
+        try
+        {
+            cursorWrapper.afterValue( new Long( 0 ), new Long( 0 ) );
+            assertTrue( cursorWrapper.next() );
+
+            IndexEntry<?, Long> next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 0 ) ) );
+            assertTrue( next.getId().equals( new Long( 1 ) ) );
+
+            assertTrue( cursorWrapper.next() );
+            next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 1 ) ) );
+            assertTrue( next.getId().equals( new Long( 1 ) ) );
+
+            cursorWrapper.afterValue( new Long( 5 ), new Long( 4 ) );
+            assertTrue( cursorWrapper.next() );
+
+            next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 5 ) ) );
+            assertTrue( next.getId().equals( new Long( 5 ) ) );
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testBefore()
+    {
+        try
+        {
+            cursorWrapper.beforeValue( new Long( 5 ), new Long( 4 ) );
+            assertTrue( cursorWrapper.next() );
+
+            IndexEntry<?, Long> next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 4 ) ) );
+            assertTrue( next.getId().equals( new Long( 5 ) ) );
+
+            assertTrue( cursorWrapper.next() );
+            next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 5 ) ) );
+            assertTrue( next.getId().equals( new Long( 5 ) ) );
+
+            assertTrue( cursorWrapper.next() );
+            next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 6 ) ) );
+            assertTrue( next.getId().equals( new Long( 7 ) ) );
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testAfterLast()
+    {
+        try
+        {
+            cursorWrapper.afterLast();
+            assertTrue( cursorWrapper.previous() );
+
+            IndexEntry<?, Long> prev = cursorWrapper.get();
+            assertTrue( prev.getValue().equals( new Long( 9 ) ) );
+            assertTrue( prev.getId().equals( new Long( 10 ) ) );
+
+            assertTrue( cursorWrapper.previous() );
+            prev = cursorWrapper.get();
+            assertTrue( prev.getValue().equals( new Long( 9 ) ) );
+            assertTrue( prev.getId().equals( new Long( 9 ) ) );
+
+            assertTrue( cursorWrapper.next() );
+
+            assertTrue( cursorWrapper.next() == false );
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testBeforeFirst()
+    {
+        try
+        {
+            cursorWrapper.beforeFirst();
+            assertTrue( cursorWrapper.next() );
+
+            IndexEntry<?, Long> next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 0 ) ) );
+            assertTrue( next.getId().equals( new Long( 0 ) ) );
+
+            assertTrue( cursorWrapper.previous() == false );
+
+            assertTrue( cursorWrapper.next() );
+            next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 0 ) ) );
+            assertTrue( next.getId().equals( new Long( 0 ) ) );
+
+            assertTrue( cursorWrapper.next() );
+            next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 0 ) ) );
+            assertTrue( next.getId().equals( new Long( 1 ) ) );
+
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testSkipKey()
+    {
+        try
+        {
+            cursorWrapper.afterValue( null, new Long( 5 ) );
+            assertTrue( cursorWrapper.next() );
+
+            IndexEntry<?, Long> next = cursorWrapper.get();
+            assertTrue( next.getValue().equals( new Long( 6 ) ) );
+            assertTrue( next.getId().equals( new Long( 7 ) ) );
+
+            cursorWrapper.beforeValue( null, new Long( 1 ) );
+            assertTrue( cursorWrapper.previous() );
+
+            IndexEntry<?, Long> prev = cursorWrapper.get();
+            assertTrue( prev.getValue().equals( new Long( 0 ) ) );
+            assertTrue( prev.getId().equals( new Long( 1 ) ) );
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    class MockIndex extends GenericIndex<Long, Entry, Long>
+    {
+        public MockIndex()
+        {
+            super( attributeOid );
+        }
+
+
+        public ForwardIndexComparator<Long, Long> getForwardIndexEntryComparator()
+        {
+            return new ForwardIndexComparator<Long, Long>( LongComparator.INSTANCE,
+                LongComparator.INSTANCE );
+        }
+
+
+        public ReverseIndexComparator<Long, Long> getReverseIndexEntryComparator()
+        {
+            return new ReverseIndexComparator<Long, Long>( LongComparator.INSTANCE,
+                LongComparator.INSTANCE );
+        }
+    }
+
+}

Modified: directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/TxnIndexCursorTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/TxnIndexCursorTest.java?rev=1195910&r1=1195909&r2=1195910&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/TxnIndexCursorTest.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/TxnIndexCursorTest.java Tue Nov  1 10:01:54 2011
@@ -37,7 +37,7 @@ import static org.junit.Assert.fail;
 public class TxnIndexCursorTest
 {
     /** index entry comparator */
-    ForwardIndexComparator<?, Long> comparator = new ForwardIndexComparator<Long, Long>( LongComparator.INSTANCE,
+    private ForwardIndexComparator<?, Long> comparator = new ForwardIndexComparator<Long, Long>( LongComparator.INSTANCE,
         LongComparator.INSTANCE );
 
     /** sorted change set for the cursor */
@@ -85,7 +85,10 @@ public class TxnIndexCursorTest
     {
         try
         {
-            cursor.close();
+            if ( cursor != null )
+            {
+                cursor.close();
+            }
         }
         catch ( Exception e )
         {



Mime
View raw message