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

svn commit: r1195359 - in /directory/apacheds/branches/apacheds-txns/core/src: main/java/org/apache/directory/server/core/txn/ test/java/org/apache/directory/server/core/txn/

Author: saya
Date: Mon Oct 31 07:11:22 2011
New Revision: 1195359

URL: http://svn.apache.org/viewvc?rev=1195359&view=rev
Log:
a test for TxnIndexCursor and some formatting and documentation.

Added:
    directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/
    directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongComparator.java
    directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongSerializer.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/src/main/java/org/apache/directory/server/core/txn/DefaultTxnLogManager.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/TxnIndexCursor.java
    directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerFactory.java

Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/DefaultTxnLogManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/DefaultTxnLogManager.java?rev=1195359&r1=1195358&r2=1195359&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/DefaultTxnLogManager.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/DefaultTxnLogManager.java Mon Oct 31 07:11:22 2011
@@ -50,13 +50,14 @@ public class DefaultTxnLogManager<ID> im
     
     
     /**
-     * TODO : doco
-     * @param logger
-     * @param txnManager
+     * Inits the the txn log manager
+     * 
+     * @param logger write ahead logger
+     * @param txnManager txn Manager
      */
     public void init( Log logger, TxnManagerInternal<ID> txnManager )
     {
-        this.wal = logger;
+        wal = logger;
         this.txnManager = txnManager;
     }
     

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=1195359&r1=1195358&r2=1195359&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 Mon Oct 31 07:11:22 2011
@@ -316,7 +316,7 @@ public class IndexCursorWrapper<ID> exte
         
         if ( positioned == false )
         {
-            afterLast();
+            beforeFirst();
         }
         
         if ((  movingNext == false ) || ( getIndex < 0 ) )

Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnIndexCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnIndexCursor.java?rev=1195359&r1=1195358&r2=1195359&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnIndexCursor.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnIndexCursor.java Mon Oct 31 07:11:22 2011
@@ -19,6 +19,7 @@
  */
 package org.apache.directory.server.core.txn;
 
+
 import org.apache.directory.server.core.api.partition.index.AbstractIndexCursor;
 import org.apache.directory.server.core.api.partition.index.IndexComparator;
 import org.apache.directory.server.core.api.partition.index.IndexEntry;
@@ -31,74 +32,79 @@ import org.apache.directory.shared.ldap.
 import java.util.Iterator;
 import java.util.NavigableSet;
 
+
 /**
+ * Provides a cursor over the index entries added by a transaction
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class TxnIndexCursor <ID> extends AbstractIndexCursor<Object, Entry, ID>
+public class TxnIndexCursor<ID> extends AbstractIndexCursor<Object, Entry, ID>
 {
     /** list of changed index entries */
-    private NavigableSet<IndexEntry<Object,ID>> changedEntries;
-    
+    private NavigableSet<IndexEntry<Object, ID>> changedEntries;
+
     /** forward or reverse index */
     private boolean forwardIndex;
-    
+
     /** whether cursor is explicitly positioned */
     private boolean positioned;
-    
+
     /** whether the moving direction is next */
     private boolean movingNext = true;
-    
+
     /** Iterator to move over the set */
-    private Iterator<IndexEntry<Object,ID>> it;
-    
+    private Iterator<IndexEntry<Object, ID>> it;
+
     /** currently available value */
-    private IndexEntry<Object,ID> availableValue;
-    
+    private IndexEntry<Object, ID> availableValue;
+
     /** unsupported operation message */
     private static final String UNSUPPORTED_MSG = I18n.err( I18n.ERR_722 );
-    
+
     /** true if the index is locked down for a key */
     private boolean onlyKey;
-    
+
+    /** True if past the only key */
+    private boolean pastOnlyKey;
+
     /** Lock down key in case of forward index */
     private Object onlyValueKey;
-    
+
     /** Lock down key in case of reverse index */
     private ID onlyIDKey;
-    
+
     /** index entry comparator */
-    private IndexComparator<Object,ID> comparator;
-   
-    
-    public TxnIndexCursor( NavigableSet<IndexEntry<Object,ID>> changedEntries, boolean forwardIndex, Object onlyValueKey, ID onlyIDKey, IndexComparator<Object,ID> comparator )
+    private IndexComparator<Object, ID> comparator;
+
+
+    public TxnIndexCursor( NavigableSet<IndexEntry<Object, ID>> changedEntries, boolean forwardIndex,
+        Object onlyValueKey, ID onlyIDKey, IndexComparator<?, ID> comparator )
     {
         this.changedEntries = changedEntries;
         this.forwardIndex = forwardIndex;
-        this.comparator = comparator;
-        
+        this.comparator = ( IndexComparator<Object, ID> ) comparator;
+
         if ( onlyValueKey != null )
         {
             this.onlyValueKey = onlyValueKey;
             onlyKey = true;
         }
-        
-        if ( changedEntries.size()  < 1 )
+
+        if ( changedEntries.size() < 1 )
         {
-            throw new IllegalArgumentException("TxnIndexCursor should not be constructed with no index  changes");
+            throw new IllegalArgumentException( "TxnIndexCursor should not be constructed with no index  changes" );
         }
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
     public void after( IndexEntry<Object, ID> element ) throws Exception
     {
-        positioned = true;
         availableValue = null;
-        movingNext = true;
-        
+
+        // If the cursor is locked down by a key, check if the key is equal to the only key we have.
         if ( onlyKey )
         {
             if ( forwardIndex )
@@ -116,10 +122,18 @@ public class TxnIndexCursor <ID> extends
                 }
             }
         }
-        
+
+        positioned = true;
+        movingNext = true;
+        pastOnlyKey = false;
+
+        /*
+         * If (key, null) is given as the element to position after, then skip all 
+         * the index elements with the given key.
+         */
         boolean skipKey = false;
-        
-        if  ( forwardIndex )
+
+        if ( forwardIndex )
         {
             if ( element.getId() == null )
             {
@@ -133,21 +147,25 @@ public class TxnIndexCursor <ID> extends
                 skipKey = true;
             }
         }
-    
+
         if ( skipKey )
-        { 
+        {
+            /*
+             *  After this call, the iterator will be position on the first value for the given key if a value for the key exists. Otherwise it
+             *  is positioned at the key past the given key.
+             */
             it = changedEntries.tailSet( element, false ).iterator();
-            
+
             boolean useLastEntry = false;
-            IndexEntry<Object,ID> indexEntry = null;
-            
+            IndexEntry<Object, ID> indexEntry = null;
+
             while ( it.hasNext() )
             {
                 indexEntry = it.next();
-                
+
                 if ( forwardIndex )
                 {
-                    if ( comparator.getValueComparator().compare( indexEntry.getValue(), element.getValue() )  != 0 )
+                    if ( comparator.getValueComparator().compare( indexEntry.getValue(), element.getValue() ) != 0 )
                     {
                         useLastEntry = true;
                         break;
@@ -155,45 +173,47 @@ public class TxnIndexCursor <ID> extends
                 }
                 else
                 {
-                    if ( comparator.getIDComparator().compare( indexEntry.getId(), element.getId() )  != 0 )
+                    if ( comparator.getIDComparator().compare( indexEntry.getId(), element.getId() ) != 0 )
                     {
                         useLastEntry = true;
                         break;
                     }
                 }
             }
-            
+
             if ( useLastEntry )
             {
+                // Position the iterator on the first element past the given key.
                 it = changedEntries.tailSet( indexEntry, true ).iterator();
             }
             else
             {
+                // There is no more elements after the given key, change the iterator direction
                 movingNext = false;
                 it = changedEntries.descendingIterator();
             }
         }
         else
         {
+            // Simply position the iterator past the given element.
             it = changedEntries.tailSet( element, false ).iterator();
         }
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
     public void before( IndexEntry<Object, ID> element ) throws Exception
     {
-        positioned = true;
         availableValue = null;
-        movingNext = true;
-        
+
+        // If the cursor is locked down by a key, check if the key is equal to the only key we have.
         if ( onlyKey )
         {
             if ( forwardIndex )
             {
-                if ( comparator.getValueComparator().compare(element.getValue(), onlyValueKey ) != 0 )
+                if ( comparator.getValueComparator().compare( element.getValue(), onlyValueKey ) != 0 )
                 {
                     throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
                 }
@@ -206,17 +226,26 @@ public class TxnIndexCursor <ID> extends
                 }
             }
         }
-        
+
+        positioned = true;
+        movingNext = true;
+        pastOnlyKey = false;
+
+        /*
+         * Position the iterator on the given element. A call to next will return this element if it exists. If 
+         * (key,null) is supplied as the element, then this will position the iterator on the first value for the
+         * given key if any value for the given key exists.
+         */
         it = changedEntries.tailSet( element, true ).iterator();
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
     public void afterValue( ID id, Object value ) throws Exception
     {
-        ForwardIndexEntry<Object,ID> indexEntry = new ForwardIndexEntry<Object,ID>();
+        ForwardIndexEntry<Object, ID> indexEntry = new ForwardIndexEntry<Object, ID>();
         indexEntry.setId( id );
         indexEntry.setValue( value );
         after( indexEntry );
@@ -228,13 +257,13 @@ public class TxnIndexCursor <ID> extends
      */
     public void beforeValue( ID id, Object value ) throws Exception
     {
-        ForwardIndexEntry<Object,ID> indexEntry = new ForwardIndexEntry<Object,ID>();
+        ForwardIndexEntry<Object, ID> indexEntry = new ForwardIndexEntry<Object, ID>();
         indexEntry.setId( id );
         indexEntry.setValue( value );
         before( indexEntry );
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
@@ -243,11 +272,13 @@ public class TxnIndexCursor <ID> extends
         positioned = true;
         availableValue = null;
         movingNext = true;
-        
+        pastOnlyKey = false;
+
         if ( onlyKey )
         {
-            ForwardIndexEntry<Object,ID> indexEntry = new ForwardIndexEntry<Object,ID>();
-            
+            // If locked down by a key, position the iterator on the first value for the given key. 
+            ForwardIndexEntry<Object, ID> indexEntry = new ForwardIndexEntry<Object, ID>();
+
             if ( forwardIndex )
             {
                 indexEntry.setValue( onlyValueKey );
@@ -256,7 +287,7 @@ public class TxnIndexCursor <ID> extends
             {
                 indexEntry.setId( onlyIDKey );
             }
-            
+
             it = changedEntries.tailSet( indexEntry, false ).iterator();
         }
         else
@@ -274,11 +305,17 @@ public class TxnIndexCursor <ID> extends
         positioned = true;
         availableValue = null;
         movingNext = false;
-        
+        pastOnlyKey = false;
+
         if ( onlyKey )
         {
-            IndexEntry<Object,ID> indexEntry = new ForwardIndexEntry<Object,ID>();
-            
+
+            /*
+             * If we are locked down by only key, then position the iterator right past the key.
+             */
+
+            IndexEntry<Object, ID> indexEntry = new ForwardIndexEntry<Object, ID>();
+
             if ( forwardIndex )
             {
                 indexEntry.setValue( onlyValueKey );
@@ -287,19 +324,18 @@ public class TxnIndexCursor <ID> extends
             {
                 indexEntry.setId( onlyIDKey );
             }
-            
+
             it = changedEntries.tailSet( indexEntry, false ).iterator();
-            
-            
+
             boolean useLastEntry = false;
-            
+
             while ( it.hasNext() )
             {
                 indexEntry = it.next();
-                
+
                 if ( forwardIndex )
                 {
-                    if ( comparator.getValueComparator().compare( indexEntry.getValue(), onlyValueKey )  != 0 )
+                    if ( comparator.getValueComparator().compare( indexEntry.getValue(), onlyValueKey ) != 0 )
                     {
                         useLastEntry = true;
                         break;
@@ -307,14 +343,14 @@ public class TxnIndexCursor <ID> extends
                 }
                 else
                 {
-                    if ( comparator.getIDComparator().compare( indexEntry.getId(), onlyIDKey )  != 0 )
+                    if ( comparator.getIDComparator().compare( indexEntry.getId(), onlyIDKey ) != 0 )
                     {
                         useLastEntry = true;
                         break;
                     }
                 }
             }
-            
+
             if ( useLastEntry )
             {
                 it = changedEntries.headSet( indexEntry, false ).descendingIterator();
@@ -329,7 +365,7 @@ public class TxnIndexCursor <ID> extends
             it = changedEntries.descendingIterator();
         }
     }
-    
+
 
     /**
      * {@inheritDoc}
@@ -337,10 +373,10 @@ public class TxnIndexCursor <ID> extends
     public boolean first() throws Exception
     {
         beforeFirst();
-        
+
         return next();
     }
-    
+
 
     /**
      * {@inheritDoc}
@@ -348,11 +384,11 @@ public class TxnIndexCursor <ID> extends
     public boolean last() throws Exception
     {
         afterLast();
-        
+
         return previous();
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
@@ -362,7 +398,8 @@ public class TxnIndexCursor <ID> extends
         {
             afterLast();
         }
-        
+
+        // If currently moving in the next() direction, then get a descending iterator using the last availableValue
         if ( movingNext == true )
         {
             if ( availableValue == null )
@@ -372,7 +409,7 @@ public class TxnIndexCursor <ID> extends
                     availableValue = it.next();
                 }
             }
-            
+
             if ( availableValue == null )
             {
                 it = changedEntries.descendingIterator();
@@ -381,23 +418,35 @@ public class TxnIndexCursor <ID> extends
             {
                 it = changedEntries.headSet( availableValue, false ).descendingIterator();
             }
-            
+
             availableValue = null;
             movingNext = false;
+            pastOnlyKey = false;
+        }
+
+        if ( pastOnlyKey )
+        {
+            return false;
         }
 
         if ( it.hasNext() )
         {
             availableValue = it.next();
-            
+
+            /*
+             * If only key and past the only key, do not make the available value null. 
+             * Repeated calls the previous will not advance iterator either. If the user
+             * calls next after this point, the available value will be used to
+             * reverse the iterator.
+             */
             if ( onlyKey )
             {
                 if ( forwardIndex )
                 {
                     if ( comparator.getValueComparator().compare( availableValue.getValue(), onlyValueKey ) != 0 )
                     {
-                        availableValue = null;
-                        
+                        pastOnlyKey = true;
+
                         return false;
                     }
                 }
@@ -405,23 +454,23 @@ public class TxnIndexCursor <ID> extends
                 {
                     if ( comparator.getIDComparator().compare( availableValue.getId(), onlyIDKey ) != 0 )
                     {
-                        availableValue = null;
-                        
+                        pastOnlyKey = true;
+
                         return false;
                     }
                 }
             }
-            
+
             return true;
         }
         else
         {
             availableValue = null;
-            
+
             return false;
         }
     }
-    
+
 
     /**
      * {@inheritDoc}
@@ -430,9 +479,10 @@ public class TxnIndexCursor <ID> extends
     {
         if ( positioned == false )
         {
-            afterLast();
+            beforeFirst();
         }
-        
+
+        // If currently moving in the previous() direction, then get a increasing iterator using the last availableValue
         if ( movingNext == false )
         {
             if ( availableValue == null )
@@ -442,33 +492,44 @@ public class TxnIndexCursor <ID> extends
                     availableValue = it.next();
                 }
             }
-            
+
             if ( availableValue == null )
             {
                 it = changedEntries.iterator();
             }
             else
             {
-                it = changedEntries.tailSet( availableValue, false ).descendingIterator();
+                it = changedEntries.tailSet( availableValue, false ).iterator();
             }
-            
+
             availableValue = null;
             movingNext = true;
+            pastOnlyKey = false;
+        }
+
+        if ( pastOnlyKey )
+        {
+            return false;
         }
 
         if ( it.hasNext() )
         {
             availableValue = it.next();
-            
 
+            /*
+             * If only key and past the only key, do not make the available value null. 
+             * Repeated calls the next will not advance iterator either. If the user
+             * calls previous after this point, the available value will be used to
+             * reverse the iterator.
+             */
             if ( onlyKey )
             {
                 if ( forwardIndex )
                 {
                     if ( comparator.getValueComparator().compare( availableValue.getValue(), onlyValueKey ) != 0 )
                     {
-                        availableValue = null;
-                        
+                        pastOnlyKey = true;
+
                         return false;
                     }
                 }
@@ -476,38 +537,38 @@ public class TxnIndexCursor <ID> extends
                 {
                     if ( comparator.getIDComparator().compare( availableValue.getId(), onlyIDKey ) != 0 )
                     {
-                        availableValue = null;
-                        
+                        pastOnlyKey = true;
+
                         return false;
                     }
                 }
             }
-            
+
             return true;
         }
         else
         {
             availableValue = null;
-            
+
             return false;
         }
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
     public IndexEntry<Object, ID> get() throws Exception
     {
-        if ( availableValue != null )
+        if ( availableValue != null && !pastOnlyKey )
         {
             return availableValue;
         }
 
         throw new InvalidCursorPositionException();
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */

Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerFactory.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerFactory.java?rev=1195359&r1=1195358&r2=1195359&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerFactory.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerFactory.java Mon Oct 31 07:11:22 2011
@@ -19,8 +19,15 @@
  */
 package org.apache.directory.server.core.txn;
 
+
 import java.util.Comparator;
 import org.apache.directory.server.core.api.partition.index.Serializer;
+import org.apache.directory.server.core.log.DefaultLog;
+import org.apache.directory.server.core.log.Log;
+import org.apache.directory.server.core.log.InvalidLogException;
+
+import java.io.IOException;
+
 
 /**
  * 
@@ -28,40 +35,73 @@ import org.apache.directory.server.core.
  */
 public class TxnManagerFactory
 {
+    /** The only txn manager */
     private static TxnManagerInternal<?> txnManager;
-    
+
+    /** The only txn log manager */
     private static TxnLogManager<?> txnLogManager;
-    
-    public static <ID> void init(Comparator<ID> idComparator, Serializer idSerializer)
+
+    /** log suffix */
+    private static String LOG_SUFFIX = "log";
+
+
+    /**
+     * 
+     * Initializes the txn managemenet layer. It creates the only instances of txn manager and txn log manager. 
+     *
+     * @param idComparator comparator for the ID type.
+     * @param idSerializer seriazlier for the ID type.
+     * @param logFolderPath log folder path for the log manager.
+     * @param logBufferSize in memory buffer size for the log manager.
+     * @param logFileSize max targer log file size for the log manager.
+     * @throws IOException thrown if initialization fails.
+     */
+    @SuppressWarnings("unchecked")
+    public static <ID> void init( Comparator<ID> idComparator, Serializer idSerializer, String logFolderPath,
+        int logBufferSize, int logFileSize ) throws IOException
     {
+        Log log = new DefaultLog();
+
+        try
+        {
+            log.init( logFolderPath, LOG_SUFFIX, logBufferSize, logFileSize );
+        }
+        catch ( InvalidLogException e )
+        {
+            throw new IOException( e );
+        }
+
         DefaultTxnManager<ID> dTxnManager;
         dTxnManager = new DefaultTxnManager<ID>();
         txnManager = dTxnManager;
-        
+
         DefaultTxnLogManager<ID> dTxnLogManager;
         dTxnLogManager = new DefaultTxnLogManager<ID>();
         txnLogManager = dTxnLogManager;
-        
-        // TODO init txn manager and log manager
-        
+        dTxnLogManager.init( log, ( TxnManagerInternal<ID> ) txnManager );
+
         dTxnManager.init( dTxnLogManager, idComparator, idSerializer );
+
     }
-    
-    
+
+
+    @SuppressWarnings("unchecked")
     public static <ID> TxnManager<ID> txnManagerInstance()
     {
-        return ( (TxnManager<ID>) txnManager );
+        return ( ( TxnManager<ID> ) txnManager );
     }
-    
-    
+
+
+    @SuppressWarnings("unchecked")
     public static <ID> TxnLogManager<ID> txnLogManagerInstance()
     {
-        return ( (TxnLogManager<ID>) txnLogManager );
+        return ( ( TxnLogManager<ID> ) txnLogManager );
     }
-    
-    
+
+
+    @SuppressWarnings("unchecked")
     static <ID> TxnManagerInternal<ID> txnManagerInternalInstance()
     {
-        return ( (TxnManagerInternal<ID>) txnManager );
+        return ( ( TxnManagerInternal<ID> ) txnManager );
     }
 }

Added: directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongComparator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongComparator.java?rev=1195359&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongComparator.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongComparator.java Mon Oct 31 07:11:22 2011
@@ -0,0 +1,38 @@
+
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+
+package org.apache.directory.server.core.txn;
+
+
+import java.util.Comparator;
+
+
+public class LongComparator implements Comparator<Long>
+{
+    public static final LongComparator INSTANCE = new LongComparator();
+
+
+    public int compare( Long l1, Long l2 )
+    {
+        return ( l1 < l2 ? -1 : ( l1.equals( l2 ) ? 0 : 1 ) );
+    }
+
+}

Added: directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongSerializer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongSerializer.java?rev=1195359&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongSerializer.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/LongSerializer.java Mon Oct 31 07:11:22 2011
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.server.core.txn;
+
+
+import java.io.IOException;
+import org.apache.directory.server.core.api.partition.index.Serializer;
+
+
+public class LongSerializer implements Serializer
+{
+    public static final LongSerializer INSTANCE = new LongSerializer();
+
+
+    public byte[] serialize( Object o ) throws IOException
+    {
+        long id = ( Long ) o;
+        byte[] bites = new byte[8];
+
+        bites[0] = ( byte ) ( id >> 56 );
+        bites[1] = ( byte ) ( id >> 48 );
+        bites[2] = ( byte ) ( id >> 40 );
+        bites[3] = ( byte ) ( id >> 32 );
+        bites[4] = ( byte ) ( id >> 24 );
+        bites[5] = ( byte ) ( id >> 16 );
+        bites[6] = ( byte ) ( id >> 8 );
+        bites[7] = ( byte ) id;
+
+        return bites;
+    }
+
+
+    public Object deserialize( byte[] bites ) throws IOException
+    {
+        long id;
+        id = bites[0] + ( ( bites[0] < 0 ) ? 256 : 0 );
+        id <<= 8;
+        id += bites[1] + ( ( bites[1] < 0 ) ? 256 : 0 );
+        id <<= 8;
+        id += bites[2] + ( ( bites[2] < 0 ) ? 256 : 0 );
+        id <<= 8;
+        id += bites[3] + ( ( bites[3] < 0 ) ? 256 : 0 );
+        id <<= 8;
+        id += bites[4] + ( ( bites[4] < 0 ) ? 256 : 0 );
+        id <<= 8;
+        id += bites[5] + ( ( bites[5] < 0 ) ? 256 : 0 );
+        id <<= 8;
+        id += bites[6] + ( ( bites[6] < 0 ) ? 256 : 0 );
+        id <<= 8;
+        id += bites[7] + ( ( bites[7] < 0 ) ? 256 : 0 );
+        return id;
+    }
+}

Added: 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=1195359&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/TxnIndexCursorTest.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/txn/TxnIndexCursorTest.java Mon Oct 31 07:11:22 2011
@@ -0,0 +1,286 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.server.core.txn;
+
+
+import java.util.TreeSet;
+
+import org.apache.directory.server.core.api.partition.index.IndexEntry;
+import org.apache.directory.server.core.api.partition.index.ForwardIndexEntry;
+import org.apache.directory.server.core.api.partition.index.ForwardIndexComparator;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+public class TxnIndexCursorTest
+{
+    /** index entry comparator */
+    ForwardIndexComparator<?, Long> comparator = new ForwardIndexComparator<Long, Long>( LongComparator.INSTANCE,
+        LongComparator.INSTANCE );
+
+    /** sorted change set for the cursor */
+    private TreeSet<IndexEntry<Object, Long>> changedSet;
+
+    /** Cursor */
+    TxnIndexCursor<Long> cursor;
+
+    /** Only Key Cursor */
+    TxnIndexCursor<Long> onlyKeyCursor;
+
+
+    @Before
+    public void setup()
+    {
+        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 );
+
+    }
+
+
+    @After
+    public void teardown()
+    {
+        try
+        {
+            cursor.close();
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+
+    }
+
+
+    @Test
+    public void testAfter()
+    {
+        try
+        {
+            cursor.afterValue( new Long( 0 ), new Long( 0 ) );
+            assertTrue( cursor.next() );
+
+            IndexEntry<?, Long> next = cursor.get();
+            assertTrue( next.getValue().equals( new Long( 1 ) ) );
+            assertTrue( next.getId().equals( new Long( 1 ) ) );
+
+            cursor.afterValue( new Long( 5 ), new Long( 5 ) );
+            assertTrue( cursor.previous() );
+
+            IndexEntry<?, Long> prev = cursor.get();
+            assertTrue( prev.getValue().equals( new Long( 4 ) ) );
+            assertTrue( prev.getId().equals( new Long( 5 ) ) );
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testBefore()
+    {
+        try
+        {
+            cursor.beforeValue( new Long( 0 ), new Long( 0 ) );
+            assertTrue( cursor.next() );
+
+            IndexEntry<?, Long> next = cursor.get();
+            assertTrue( next.getValue().equals( new Long( 0 ) ) );
+            assertTrue( next.getId().equals( new Long( 0 ) ) );
+
+            cursor.beforeValue( new Long( 5 ), new Long( 4 ) );
+            assertTrue( cursor.previous() );
+
+            IndexEntry<?, Long> prev = cursor.get();
+            assertTrue( prev.getValue().equals( new Long( 4 ) ) );
+            assertTrue( prev.getId().equals( new Long( 4 ) ) );
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testAfterLast()
+    {
+        try
+        {
+            cursor.afterLast();
+            assertTrue( cursor.previous() );
+
+            IndexEntry<?, Long> prev = cursor.get();
+            assertTrue( prev.getValue().equals( new Long( 9 ) ) );
+            assertTrue( prev.getId().equals( new Long( 10 ) ) );
+
+            assertTrue( cursor.next() == false );
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testBeforeFirst()
+    {
+        try
+        {
+            cursor.beforeFirst();
+            assertTrue( cursor.next() );
+
+            IndexEntry<?, Long> next = cursor.get();
+            assertTrue( next.getValue().equals( new Long( 0 ) ) );
+            assertTrue( next.getId().equals( new Long( 0 ) ) );
+
+            assertTrue( cursor.previous() == false );
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testSkipKey()
+    {
+        try
+        {
+            cursor.afterValue( null, new Long( 4 ) );
+            assertTrue( cursor.next() );
+
+            IndexEntry<?, Long> next = cursor.get();
+            assertTrue( next.getValue().equals( new Long( 6 ) ) );
+            assertTrue( next.getId().equals( new Long( 6 ) ) );
+
+            cursor.beforeValue( null, new Long( 4 ) );
+            assertTrue( cursor.next() );
+
+            next = cursor.get();
+            assertTrue( next.getValue().equals( new Long( 4 ) ) );
+            assertTrue( next.getId().equals( new Long( 4 ) ) );
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testLockDownByExistingKey()
+    {
+        onlyKeyCursor = new TxnIndexCursor<Long>( changedSet, true, new Long( 7 ), null, comparator );
+        try
+        {
+            onlyKeyCursor.beforeFirst();
+
+            assertTrue( onlyKeyCursor.next() );
+            IndexEntry<?, Long> next = onlyKeyCursor.get();
+            assertTrue( next.getValue().equals( new Long( 7 ) ) );
+            assertTrue( next.getId().equals( new Long( 7 ) ) );
+
+            assertTrue( onlyKeyCursor.next() );
+            next = onlyKeyCursor.get();
+            assertTrue( next.getValue().equals( new Long( 7 ) ) );
+            assertTrue( next.getId().equals( new Long( 8 ) ) );
+
+            assertTrue( onlyKeyCursor.next() == false );
+            assertTrue( onlyKeyCursor.previous() );
+            IndexEntry<?, Long> prev = onlyKeyCursor.get();
+            assertTrue( prev.getValue().equals( new Long( 7 ) ) );
+            assertTrue( prev.getId().equals( new Long( 8 ) ) );
+
+            assertTrue( onlyKeyCursor.previous() );
+            prev = onlyKeyCursor.get();
+            assertTrue( prev.getValue().equals( new Long( 7 ) ) );
+            assertTrue( prev.getId().equals( new Long( 7 ) ) );
+
+            assertTrue( onlyKeyCursor.previous() == false );
+            assertTrue( onlyKeyCursor.previous() == false );
+            assertTrue( onlyKeyCursor.next() == true );
+            next = onlyKeyCursor.get();
+            assertTrue( next.getValue().equals( new Long( 7 ) ) );
+            assertTrue( next.getId().equals( new Long( 7 ) ) );
+
+            onlyKeyCursor.afterValue( null, new Long( 7 ) );
+
+            assertTrue( onlyKeyCursor.next() == false );
+            assertTrue( onlyKeyCursor.previous() );
+            prev = onlyKeyCursor.get();
+            assertTrue( prev.getValue().equals( new Long( 7 ) ) );
+            assertTrue( prev.getId().equals( new Long( 8 ) ) );
+
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testLockDownByNonExistingKey()
+    {
+        onlyKeyCursor = new TxnIndexCursor<Long>( changedSet, true, new Long( 5 ), null, comparator );
+        try
+        {
+            onlyKeyCursor.beforeFirst();
+            assertTrue( onlyKeyCursor.next() == false );
+            assertTrue( onlyKeyCursor.previous() == false );
+
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+}