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/18 15:11:43 UTC
svn commit: r1185638 [1/2] - in /directory/apacheds/branches/apacheds-txns:
core-api/src/main/java/org/apache/directory/server/core/partition/index/
core-api/src/main/java/org/apache/directory/server/core/txn/
core-api/src/main/java/org/apache/director...
Author: saya
Date: Tue Oct 18 13:11:42 2011
New Revision: 1185638
URL: http://svn.apache.org/viewvc?rev=1185638&view=rev
Log:
changes to merge reads from master and index reads with txn log:
logedits: log edits to keep track entry modifications, entry add/delete and index changes.
ReadWriteTxn and TxnLogManager: As data log edits are added a summary of index changes for the current txn is built. This summary is of the for<partitionDN, attributeOID, sorted set of index changes>
TxnIndexCursor: this implements a cursor interface for a single txn for a single index. Since index changes are kept memory, this cursor is built using an iterator.
IndexCursorWrapper.java: This wraps a partition index and creates a transactionally consistent view of it using the wrapped index and TxnIdexCursors for the txns that the current txn depends on.This basically implements a merge sort of various index cursors.
TODO: finish MastertableWrapper, add IndexWrapper
Added:
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ForwardIndexComparator.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ReverseIndexComparator.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Serializer.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/MasterTableWrapper.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
directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/
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/EntryAddDelete.java
directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/EntryChange.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/main/java/org/apache/directory/server/core/txn/logedit/TxnStateChange.java
Removed:
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/TxnStateChange.java
Modified:
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/GenericIndex.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Index.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnLogManager.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnManager.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/AbstractLogEdit.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/LogEdit.java
directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/AbstractTransaction.java
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/DefaultTxnManager.java
directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadOnlyTxn.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/Transaction.java
directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerInternal.java
directory/apacheds/branches/apacheds-txns/core/src/test/java/org/apache/directory/server/core/log/LogFlushScanTest.java
directory/apacheds/branches/apacheds-txns/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmIndex.java
directory/apacheds/branches/apacheds-txns/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/impl/avl/AvlIndex.java
Added: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ForwardIndexComparator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ForwardIndexComparator.java?rev=1185638&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ForwardIndexComparator.java (added)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ForwardIndexComparator.java Tue Oct 18 13:11:42 2011
@@ -0,0 +1,48 @@
+
+package org.apache.directory.server.core.partition.index;
+
+import java.util.Comparator;
+
+public class ForwardIndexComparator<V, ID> implements Comparator<IndexEntry<V,ID>>
+{
+ Comparator<V> keyComparator;
+ Comparator<ID> valueComparator;
+
+ public ForwardIndexComparator( Comparator<V> keyComparator, Comparator<ID> valueComparator )
+ {
+ this.keyComparator = keyComparator;
+ this.valueComparator = valueComparator;
+ }
+
+ public int compare( IndexEntry<V, ID> entry1, IndexEntry<V, ID> entry2 )
+ {
+ V value1 = entry1.getValue();
+ V value2 = entry2.getValue();
+ ID id1 = entry1.getId();
+ ID id2 = entry2.getId();
+
+ int result = keyComparator.compare( value1, value2 );
+
+ if ( result == 0 )
+ {
+ if ( id1 == id2 )
+ {
+ result = 0;
+ }
+ else if ( id1 == null )
+ {
+ result = -1;
+ }
+ else if ( id2 == null )
+ {
+ result = 1;
+ }
+ else
+ {
+ result = valueComparator.compare( id1, id2 );
+ }
+ }
+
+ return result;
+ }
+}
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/GenericIndex.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/GenericIndex.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/GenericIndex.java (original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/GenericIndex.java Tue Oct 18 13:11:42 2011
@@ -262,6 +262,17 @@ public class GenericIndex<K, O, ID> exte
}
+ public ForwardIndexComparator<K,ID> getForwardIndexEntryComparator()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public ReverseIndexComparator<K,ID> getReverseIndexEntryComparator()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+
public void setWkDirPath( URI wkDirPath )
{
this.wkDirPath = wkDirPath;
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Index.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Index.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Index.java (original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Index.java Tue Oct 18 13:11:42 2011
@@ -258,6 +258,9 @@ public interface Index<K, O, ID>
boolean reverseLessOrEq( ID id, K attrVal ) throws Exception;
+ public ForwardIndexComparator<K,ID> getForwardIndexEntryComparator();
+
+ public ReverseIndexComparator<K,ID> getReverseIndexEntryComparator();
void close() throws Exception;
Added: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ReverseIndexComparator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ReverseIndexComparator.java?rev=1185638&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ReverseIndexComparator.java (added)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/ReverseIndexComparator.java Tue Oct 18 13:11:42 2011
@@ -0,0 +1,48 @@
+
+package org.apache.directory.server.core.partition.index;
+
+import java.util.Comparator;
+
+public class ReverseIndexComparator<V, ID> implements Comparator<IndexEntry<V, ID>>
+{
+ Comparator<V> keyComparator;
+ Comparator<ID> valueComparator;
+
+ public ReverseIndexComparator( Comparator<V> keyComparator, Comparator<ID> valueComparator )
+ {
+ this.keyComparator = keyComparator;
+ this.valueComparator = valueComparator;
+ }
+
+ public int compare( IndexEntry<V, ID> entry1, IndexEntry<V, ID> entry2 )
+ {
+ V value1 = entry1.getValue();
+ V value2 = entry2.getValue();
+ ID id1 = entry1.getId();
+ ID id2 = entry2.getId();
+
+ int result = valueComparator.compare( id1, id2 );
+
+ if ( result == 0 )
+ {
+ if ( value1 == value2 )
+ {
+ result = 0;
+ }
+ else if ( value1 == null )
+ {
+ result = -1;
+ }
+ else if ( value2 == null )
+ {
+ result = 1;
+ }
+ else
+ {
+ result = keyComparator.compare( value1, value2 );
+ }
+ }
+
+ return result;
+ }
+}
Added: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Serializer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Serializer.java?rev=1185638&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Serializer.java (added)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/partition/index/Serializer.java Tue Oct 18 13:11:42 2011
@@ -0,0 +1,25 @@
+
+package org.apache.directory.server.core.partition.index;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+public interface Serializer
+{
+ /**
+ * Serialize the content of an object into a byte array.
+ *
+ * @param obj Object to serialize
+ * @return a byte array representing the object's state
+ */
+ public byte[] serialize( Object obj ) throws IOException;
+
+
+ /**
+ * Deserialize the content of an object from a byte array.
+ *
+ * @param serialized Byte array representation of the object
+ * @return deserialized object
+ */
+ public Object deserialize( byte[] serialized ) throws IOException;
+}
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnLogManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnLogManager.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnLogManager.java (original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/TxnLogManager.java Tue Oct 18 13:11:42 2011
@@ -4,12 +4,16 @@ package org.apache.directory.server.core
import org.apache.directory.server.core.txn.logedit.LogEdit;
import org.apache.directory.server.core.log.UserLogRecord;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.name.Dn;
import java.io.IOException;
-public interface TxnLogManager
+public interface TxnLogManager<ID>
{
- public void log( LogEdit logEdit, boolean sync ) throws IOException;
+ public void log( LogEdit<ID> logEdit, boolean sync ) throws IOException;
public void log( UserLogRecord logRecord, boolean sync ) throws IOException;
+
+ public Entry mergeUpdates(Dn partitionDN, ID entryID, Entry entry );
}
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=1185638&r1=1185637&r2=1185638&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 Oct 18 13:11:42 2011
@@ -2,12 +2,18 @@
package org.apache.directory.server.core.txn;
import java.io.IOException;
+import org.apache.directory.server.core.partition.index.Serializer;
+import java.util.Comparator;
-public interface TxnManager
+public interface TxnManager<ID>
{
public void beginTransaction( boolean readOnly ) throws IOException;
public void commitTransaction() throws IOException;
public void abortTransaction() throws IOException;
+
+ public Comparator<ID> getIDComparator();
+
+ public Serializer getIDSerializer();
}
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/AbstractLogEdit.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/AbstractLogEdit.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/AbstractLogEdit.java (original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/AbstractLogEdit.java Tue Oct 18 13:11:42 2011
@@ -3,7 +3,7 @@ package org.apache.directory.server.core
import org.apache.directory.server.core.log.LogAnchor;
-public abstract class AbstractLogEdit implements LogEdit
+public abstract class AbstractLogEdit<ID> implements LogEdit<ID>
{
/** position in the wal */
private transient LogAnchor logAnchor = new LogAnchor();
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/LogEdit.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/LogEdit.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/LogEdit.java (original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/txn/logedit/LogEdit.java Tue Oct 18 13:11:42 2011
@@ -5,7 +5,7 @@ import org.apache.directory.server.core.
import java.io.Externalizable;
-public interface LogEdit extends Externalizable
+public interface LogEdit<ID> extends Externalizable
{
/**
* Returns the position the edit is inserted in the wal.
Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/AbstractTransaction.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/AbstractTransaction.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/AbstractTransaction.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/AbstractTransaction.java Tue Oct 18 13:11:42 2011
@@ -3,8 +3,12 @@ package org.apache.directory.server.core
import java.util.List;
import java.util.ArrayList;
+import java.util.Iterator;
-abstract class AbstractTransaction implements Transaction
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.name.Dn;
+
+abstract class AbstractTransaction<ID> implements Transaction<ID>
{
/** Logical time(LSN in the wal) when the txn began */
long startTime;
@@ -16,7 +20,7 @@ abstract class AbstractTransaction imple
State txnState;
/** List of txns that this txn depends */
- List<ReadWriteTxn> txnsToCheck = new ArrayList<ReadWriteTxn>();
+ List<ReadWriteTxn<ID>> txnsToCheck = new ArrayList<ReadWriteTxn<ID>>();
public AbstractTransaction( )
@@ -70,7 +74,7 @@ abstract class AbstractTransaction imple
/**
* {@inheritDoc}
*/
- public List<ReadWriteTxn> getTxnsToCheck()
+ public List<ReadWriteTxn<ID>> getTxnsToCheck()
{
return this.txnsToCheck;
}
@@ -91,5 +95,28 @@ abstract class AbstractTransaction imple
this.txnState = newState;
}
+ public Entry mergeUpdates( Dn partitionDn, ID entryID, Entry entry )
+ {
+ Entry prevEntry = entry;
+ Entry curEntry = entry;
+ ReadWriteTxn<ID> curTxn;
+ boolean cloneOnChange = true;
+
+ Iterator<ReadWriteTxn<ID>> it = txnsToCheck.iterator();
+
+ while ( it.hasNext() )
+ {
+ curTxn = it.next();
+ curEntry = curTxn.applyUpdatesToEntry( partitionDn, entryID, curEntry, cloneOnChange );
+
+ if ( curEntry != prevEntry )
+ {
+ cloneOnChange = false;
+ }
+ }
+
+ return curEntry;
+ }
+
}
\ No newline at end of file
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=1185638&r1=1185637&r2=1185638&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 Tue Oct 18 13:11:42 2011
@@ -9,20 +9,21 @@ import org.apache.directory.server.core.
import org.apache.directory.server.core.log.Log;
import org.apache.directory.server.core.log.InvalidLogException;
-
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.name.Dn;
import org.apache.directory.server.core.txn.logedit.LogEdit;
-public class DefaultTxnLogManager implements TxnLogManager
+public class DefaultTxnLogManager<ID> implements TxnLogManager<ID>
{
/** Write ahea log */
Log wal;
/** Txn Manager */
- TxnManagerInternal txnManager;
+ TxnManagerInternal<ID> txnManager;
- public void init( Log logger, TxnManagerInternal txnManager )
+ public void init( Log logger, TxnManagerInternal<ID> txnManager )
{
this.wal = logger;
this.txnManager = txnManager;
@@ -30,16 +31,16 @@ public class DefaultTxnLogManager implem
/**
* {@inheritDoc}
*/
- public void log( LogEdit logEdit, boolean sync ) throws IOException
+ public void log( LogEdit<ID> logEdit, boolean sync ) throws IOException
{
- Transaction curTxn = txnManager.getCurTxn();
+ Transaction<ID> curTxn = txnManager.getCurTxn();
if ( ( curTxn == null ) || ( ! ( curTxn instanceof ReadWriteTxn ) ) )
{
throw new IllegalStateException( "Trying to log logedit without ReadWriteTxn" );
}
- ReadWriteTxn txn = (ReadWriteTxn)curTxn;
+ ReadWriteTxn<ID> txn = (ReadWriteTxn<ID>)curTxn;
UserLogRecord logRecord = txn.getUserLogRecord();
@@ -73,7 +74,7 @@ public class DefaultTxnLogManager implem
this.log( logRecord, sync );
logEdit.getLogAnchor().resetLogAnchor( logRecord.getLogAnchor() );
- txn.getEdits().add( logEdit );
+ txn.addLogEdit( logEdit );
}
/**
@@ -92,4 +93,20 @@ public class DefaultTxnLogManager implem
}
+ /**
+ * {@inheritDoc}
+ */
+ public Entry mergeUpdates(Dn partitionDn, ID entryID, Entry entry )
+ {
+ Transaction<ID> curTxn = txnManager.getCurTxn();
+
+ if ( ( curTxn == null ) )
+ {
+ throw new IllegalStateException( "Trying to merge with log wihout txn" );
+ }
+
+ return curTxn.mergeUpdates( partitionDn, entryID, entry );
+ }
+
+
}
Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/DefaultTxnManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/DefaultTxnManager.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/DefaultTxnManager.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/DefaultTxnManager.java Tue Oct 18 13:11:42 2011
@@ -1,14 +1,14 @@
package org.apache.directory.server.core.txn;
+import org.apache.directory.server.core.partition.index.Serializer;
import org.apache.directory.server.core.txn.logedit.TxnStateChange;
import org.apache.directory.server.core.log.LogAnchor;
-import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -21,33 +21,38 @@ import java.util.concurrent.atomic.Atomi
import java.util.concurrent.atomic.AtomicLong;
import org.apache.directory.server.core.log.UserLogRecord;
-import org.apache.directory.server.core.log.LogAnchor;
import java.io.IOException;
-public class DefaultTxnManager implements TxnManager, TxnManagerInternal
+public class DefaultTxnManager<ID> implements TxnManagerInternal<ID>
{
/** wal log manager */
- TxnLogManager txnLogManager;
+ private TxnLogManager<ID> txnLogManager;
/** List of committed txns in commit LSN order */
- ConcurrentLinkedQueue<ReadWriteTxn> committedQueue = new ConcurrentLinkedQueue<ReadWriteTxn>();
+ private ConcurrentLinkedQueue<ReadWriteTxn<ID>> committedQueue = new ConcurrentLinkedQueue<ReadWriteTxn<ID>>();
/** Verify lock under which txn verification is done */
- Lock verifyLock = new ReentrantLock();
+ private Lock verifyLock = new ReentrantLock();
/** Used to assign start and commit version numbers to writeTxns */
- Lock writeTxnsLock = new ReentrantLock();
+ private Lock writeTxnsLock = new ReentrantLock();
/** Latest committed txn on which read only txns can depend */
- AtomicReference<ReadWriteTxn> latestCommittedTxn = new AtomicReference<ReadWriteTxn>();
+ private AtomicReference<ReadWriteTxn<ID>> latestCommittedTxn = new AtomicReference<ReadWriteTxn<ID>>();
/** Latest verified write txn */
- AtomicReference<ReadWriteTxn> latestVerifiedTxn = new AtomicReference<ReadWriteTxn>();
+ private AtomicReference<ReadWriteTxn<ID>> latestVerifiedTxn = new AtomicReference<ReadWriteTxn<ID>>();
/** Latest flushed txn's logical commit time */
- AtomicLong latestFlushedTxnLSN = new AtomicLong( 0 );
+ private AtomicLong latestFlushedTxnLSN = new AtomicLong( 0 );
+
+ /** ID comparator */
+ private Comparator<ID> idComparator;
+
+ /** ID serializer */
+ private Serializer idSerializer ;
/** Per thread txn context */
static final ThreadLocal < Transaction > txnVar =
@@ -60,9 +65,27 @@ public class DefaultTxnManager implement
}
};
- public void init( TxnLogManager txnLogManager )
+ public void init( TxnLogManager<ID> txnLogManager, Comparator<ID> idComparator, Serializer idSerializer )
{
this.txnLogManager = txnLogManager;
+ this.idComparator = idComparator;
+ this.idSerializer = idSerializer;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Comparator<ID> getIDComparator()
+ {
+ return this.idComparator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Serializer getIDSerializer()
+ {
+ return this.idSerializer;
}
/**
@@ -70,7 +93,7 @@ public class DefaultTxnManager implement
*/
public void beginTransaction( boolean readOnly ) throws IOException
{
- Transaction curTxn = txnVar.get();
+ Transaction<ID> curTxn = this.getCurTxn();
if ( curTxn != null )
{
@@ -94,7 +117,7 @@ public class DefaultTxnManager implement
*/
public void commitTransaction() throws IOException
{
- Transaction txn = txnVar.get();
+ Transaction<ID> txn = this.getCurTxn();
if ( txn == null )
{
@@ -109,7 +132,7 @@ public class DefaultTxnManager implement
}
else
{
- this.commitReadWriteTxn( (ReadWriteTxn)txn );
+ this.commitReadWriteTxn( (ReadWriteTxn<ID>)txn );
}
txnVar.set( null );
@@ -121,7 +144,7 @@ public class DefaultTxnManager implement
*/
public void abortTransaction() throws IOException
{
- Transaction txn = txnVar.get();
+ Transaction<ID> txn = this.getCurTxn();
if ( txn == null )
{
@@ -133,7 +156,7 @@ public class DefaultTxnManager implement
if ( txn instanceof ReadWriteTxn )
{
- this.abortReadWriteTxn( (ReadWriteTxn)txn );
+ this.abortReadWriteTxn( (ReadWriteTxn<ID>)txn );
}
txn.abortTxn();
@@ -143,15 +166,16 @@ public class DefaultTxnManager implement
/**
* {@inheritDoc}
*/
- public Transaction getCurTxn()
+ @SuppressWarnings("unchecked")
+ public Transaction<ID> getCurTxn()
{
- return txnVar.get();
+ return (Transaction<ID>)txnVar.get();
}
private void beginReadOnlyTxn()
{
- ReadOnlyTxn txn = new ReadOnlyTxn();
- ReadWriteTxn lastTxnToCheck = null;
+ ReadOnlyTxn<ID> txn = new ReadOnlyTxn<ID>();
+ ReadWriteTxn<ID> lastTxnToCheck = null;
do
{
@@ -176,18 +200,19 @@ public class DefaultTxnManager implement
startTime = LogAnchor.UNKNOWN_LSN;
}
+ txn.startTxn( startTime );
+
this.buildCheckList( txn, lastTxnToCheck );
txnVar.set( txn );
}
private void beginReadWriteTxn() throws IOException
{
- long txnID;
- ReadWriteTxn txn = new ReadWriteTxn();
+ ReadWriteTxn<ID> txn = new ReadWriteTxn<ID>();
UserLogRecord logRecord = txn.getUserLogRecord();
- TxnStateChange txnRecord = new TxnStateChange( LogAnchor.UNKNOWN_LSN,
+ TxnStateChange<ID> txnRecord = new TxnStateChange<ID>( LogAnchor.UNKNOWN_LSN,
TxnStateChange.State.TXN_BEGIN );
ObjectOutputStream out = null;
ByteArrayOutputStream bout = null;
@@ -217,7 +242,7 @@ public class DefaultTxnManager implement
logRecord.setData( data, data.length );
- ReadWriteTxn lastTxnToCheck = null;
+ ReadWriteTxn<ID> lastTxnToCheck = null;
writeTxnsLock.lock();
try
@@ -250,15 +275,15 @@ public class DefaultTxnManager implement
- private void buildCheckList( Transaction txn, ReadWriteTxn lastTxnToCheck )
+ private void buildCheckList( Transaction<ID> txn, ReadWriteTxn<ID> lastTxnToCheck )
{
if ( lastTxnToCheck != null )
{
long lastLSN = lastTxnToCheck.getCommitTime();
- ReadWriteTxn toAdd;
+ ReadWriteTxn<ID> toAdd;
- List<ReadWriteTxn> toCheckList = txn.getTxnsToCheck();
- Iterator<ReadWriteTxn> it = committedQueue.iterator();
+ List<ReadWriteTxn<ID>> toCheckList = txn.getTxnsToCheck();
+ Iterator<ReadWriteTxn<ID>> it = committedQueue.iterator();
while ( it.hasNext() )
{
toAdd = it.next();
@@ -277,7 +302,7 @@ public class DefaultTxnManager implement
long flushedLSN = latestFlushedTxnLSN.get();
it = toCheckList.iterator();
- ReadWriteTxn toCheck;
+ ReadWriteTxn<ID> toCheck;
while ( it.hasNext() )
{
toCheck = it.next();
@@ -292,13 +317,13 @@ public class DefaultTxnManager implement
}
- private void prepareForEndingTxn( Transaction txn )
+ private void prepareForEndingTxn( Transaction<ID> txn )
{
- List<ReadWriteTxn> toCheck = txn.getTxnsToCheck();
+ List<ReadWriteTxn<ID>> toCheck = txn.getTxnsToCheck();
if ( toCheck.size() > 0 )
{
- ReadWriteTxn lastTxnToCheck = toCheck.get( toCheck.size() - 1 );
+ ReadWriteTxn<ID> lastTxnToCheck = toCheck.get( toCheck.size() - 1 );
if ( lastTxnToCheck.commitTime != txn.getStartTime() )
{
@@ -316,11 +341,11 @@ public class DefaultTxnManager implement
}
}
- private void commitReadWriteTxn( ReadWriteTxn txn ) throws IOException
+ private void commitReadWriteTxn( ReadWriteTxn<ID> txn ) throws IOException
{
UserLogRecord logRecord = txn.getUserLogRecord();
- TxnStateChange txnRecord = new TxnStateChange( txn.getStartTime(),
+ TxnStateChange<ID> txnRecord = new TxnStateChange<ID>( txn.getStartTime(),
TxnStateChange.State.TXN_COMMIT );
ObjectOutputStream out = null;
ByteArrayOutputStream bout = null;
@@ -374,11 +399,11 @@ public class DefaultTxnManager implement
}
- private void abortReadWriteTxn( ReadWriteTxn txn ) throws IOException
+ private void abortReadWriteTxn( ReadWriteTxn<ID> txn ) throws IOException
{
UserLogRecord logRecord = txn.getUserLogRecord();
- TxnStateChange txnRecord = new TxnStateChange( txn.getStartTime(),
+ TxnStateChange<ID> txnRecord = new TxnStateChange<ID>( txn.getStartTime(),
TxnStateChange.State.TXN_ABORT );
ObjectOutputStream out = null;
ByteArrayOutputStream bout = null;
Added: 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=1185638&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/IndexCursorWrapper.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/IndexCursorWrapper.java Tue Oct 18 13:11:42 2011
@@ -0,0 +1,570 @@
+
+package org.apache.directory.server.core.txn;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import org.apache.directory.server.core.partition.index.AbstractIndexCursor;
+import org.apache.directory.server.core.partition.index.ForwardIndexEntry;
+import org.apache.directory.server.core.partition.index.IndexCursor;
+import org.apache.directory.server.core.partition.index.IndexEntry;
+import org.apache.directory.server.i18n.I18n;
+
+import org.apache.directory.shared.ldap.model.cursor.InvalidCursorPositionException;
+import org.apache.directory.shared.ldap.model.name.Dn;
+
+public class IndexCursorWrapper<V, E, ID> extends AbstractIndexCursor<V, E, ID>
+{
+ /** Cursors to merge */
+ private ArrayList<IndexCursor<V,E,ID>> cursors;
+
+ /** list of values available per cursor */
+ private ArrayList<IndexEntry<V,ID>> values;
+
+ /** index get should get the value from */
+ private int getIndex = -1;
+
+ /** Dn of the partition */
+ private Dn partitionDn;
+
+ /** Index attribute oid */
+ private String attributeOid;
+
+ /** whether this is a cursor on forward or reverse index */
+ private boolean forwardIndex;
+
+ /** List of txns that this cursor depends on */
+ private ArrayList<ReadWriteTxn<ID>> txns;
+
+ /** True if cursor is positioned */
+ private boolean positioned;
+
+ /** direction of the move */
+ boolean movingNext = true;
+
+ /** Comparator used to order the index entries */
+ private Comparator<IndexEntry<V,ID>> comparator;
+
+ /** unsupported operation message */
+ private static final String UNSUPPORTED_MSG = I18n.err( I18n.ERR_722 );
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void after( IndexEntry<V, ID> element ) throws Exception
+ {
+ int idx;
+ positioned = true;
+ movingNext = true;
+ IndexCursor<V,E,ID> cursor;
+
+ checkNotClosed( "after()" );
+
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ values.set( idx, null );
+ cursor = cursors.get( idx );
+ if( cursor != null )
+ {
+ cursor.after( element );
+ }
+ }
+
+ getIndex = -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void before( IndexEntry<V, ID> element ) throws Exception
+ {
+ int idx;
+ positioned = true;
+ movingNext = true;
+ IndexCursor<V,E,ID> cursor;
+
+ checkNotClosed( "before()" );
+
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ values.set( idx, null );
+ cursor = cursors.get( idx );
+ if( cursor != null )
+ {
+ cursor.before( element );
+ }
+ }
+
+ getIndex = -1;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterValue( ID id, V value ) throws Exception
+ {
+ int idx;
+ positioned = true;
+ movingNext = true;
+ IndexCursor<V,E,ID> cursor;
+
+ checkNotClosed( "afterValue()" );
+
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ values.set( idx, null );
+ cursor = cursors.get( idx );
+ if( cursor != null )
+ {
+ cursor.afterValue( id, value );
+ }
+ }
+
+ getIndex = -1;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeValue( ID id, V value ) throws Exception
+ {
+ int idx;
+ positioned = true;
+ movingNext = true;
+ IndexCursor<V,E,ID> cursor;
+
+ checkNotClosed( "beforeValue()" );
+
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ values.set( idx, null );
+ cursor = cursors.get( idx );
+ if( cursor != null )
+ {
+ cursor.beforeValue( id, value );
+ }
+ }
+
+ getIndex = -1;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeFirst() throws Exception
+ {
+ int idx;
+ positioned = true;
+ movingNext = true;
+ IndexCursor<V,E,ID> cursor;
+
+ checkNotClosed( "beforeFirst()" );
+
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ values.set( idx, null );
+ cursor = cursors.get( idx );
+ if( cursor != null )
+ {
+ cursor.beforeFirst();
+ }
+ }
+
+ getIndex = -1;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterLast() throws Exception
+ {
+ int idx;
+ positioned = true;
+ movingNext = false;
+ IndexCursor<V,E,ID> cursor;
+
+ checkNotClosed( "afterLast()" );
+
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ values.set( idx, null );
+ cursor = cursors.get( idx );
+ if( cursor != null )
+ {
+ cursor.afterLast( );
+ }
+
+ }
+
+ getIndex = -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean first() throws Exception
+ {
+ this.beforeFirst();
+ return this.next();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean last() throws Exception
+ {
+ this.afterLast();
+ return this.previous();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean next() throws Exception
+ {
+ IndexCursor<V,E,ID> cursor;
+ IndexEntry<V,ID> minValue;
+ IndexEntry<V,ID> value;
+
+ checkNotClosed( "next()" );
+
+ IndexEntry<V,ID> lastValue = null;
+ if ( getIndex >= 0 )
+ {
+ lastValue = values.get( getIndex );
+ }
+
+ int idx;
+ if ( positioned == false )
+ {
+ afterLast();
+ }
+
+ if ( movingNext == false || ( getIndex < 0 ) )
+ {
+ minValue = null;
+ getIndex = -1;
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ cursor = cursors.get( idx );
+ if ( cursor != null && cursor.next() )
+ {
+ value = cursor.get();
+ if ( ( getIndex < 0 ) || ( comparator.compare( value, minValue ) < 0 ) )
+ {
+ minValue = value;
+ getIndex = idx;
+ }
+
+ values.set( idx, value );
+ }
+ else
+ {
+ values.set( idx, null );
+ }
+ }
+
+ }
+ else
+ {
+ // Move the last cursor we did a get from and recompute minimum
+ this.recomputeMinimum();
+ }
+
+ int txnIdx;
+ ReadWriteTxn<ID> curTxn;
+ boolean valueDeleted;
+ do
+ {
+ if ( getIndex < 0 )
+ {
+ break;
+ }
+
+ value = values.get( getIndex );
+
+ txnIdx = getIndex;
+ if ( txnIdx > 0 )
+ {
+ txnIdx--;
+ }
+
+ valueDeleted = false;
+ for ( ; txnIdx < txns.size(); txnIdx++ )
+ {
+ curTxn = txns.get( txnIdx );
+
+ // TODO check for index entry delete here
+ if ( curTxn!= null)
+ {
+ valueDeleted = true;
+ break;
+ }
+ }
+
+ if ( valueDeleted == false && ( lastValue == null || ( comparator.compare( value, lastValue ) > 0 ) ) )
+ {
+ break;
+ }
+
+ // Recompute minimum
+ this.recomputeMinimum();
+
+ } while ( true );
+
+ return ( getIndex >= 0 );
+
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean previous() throws Exception
+ {
+ IndexCursor<V,E,ID> cursor;
+ IndexEntry<V,ID> maxValue;
+ IndexEntry<V,ID> value;
+
+ checkNotClosed( "previous()" );
+
+ IndexEntry<V,ID> lastValue = null;
+ if ( getIndex >= 0 )
+ {
+ lastValue = values.get( getIndex );
+ }
+
+ int idx;
+ if ( positioned == false )
+ {
+ afterLast();
+ }
+
+ if ( movingNext == false || ( getIndex < 0 ) )
+ {
+ maxValue = null;
+ getIndex = -1;
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ cursor = cursors.get( idx );
+ if ( cursor != null && cursor.next() )
+ {
+ value = cursor.get();
+ if ( ( getIndex < 0 ) || ( comparator.compare( value, maxValue ) > 0 ) )
+ {
+ maxValue = value;
+ getIndex = idx;
+ }
+
+ values.set( idx, value );
+ }
+ else
+ {
+ values.set( idx, null );
+ }
+ }
+
+ }
+ else
+ {
+ // Move the last cursor we did a get from and recompute maximum
+ this.recomputeMaximum();
+ }
+
+ int txnIdx;
+ ReadWriteTxn<ID> curTxn;
+ boolean valueDeleted;
+ do
+ {
+ if ( getIndex < 0 )
+ {
+ break;
+ }
+
+ value = values.get( getIndex );
+
+ txnIdx = getIndex;
+ if ( txnIdx > 0 )
+ {
+ txnIdx--;
+ }
+
+ valueDeleted = false;
+ for ( ; txnIdx < txns.size(); txnIdx++ )
+ {
+ curTxn = txns.get( txnIdx );
+
+ // TODO check for index entry delete here
+ if ( curTxn!= null)
+ {
+ valueDeleted = true;
+ break;
+ }
+ }
+
+ if ( valueDeleted == false && ( lastValue == null || ( comparator.compare( value, lastValue ) < 0 ) ) )
+ {
+ break;
+ }
+
+ // Recompute maximum
+ this.recomputeMaximum();
+
+ } while ( true );
+
+ return ( getIndex >= 0 );
+
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public IndexEntry<V, ID> get() throws Exception
+ {
+ checkNotClosed( "get()" );
+
+ if ( getIndex >= 0 )
+ {
+ IndexEntry<V,ID> value = values.get( getIndex );
+
+ if ( value == null )
+ {
+ throw new IllegalStateException( "getIndex points to a null value" );
+ }
+
+ return value;
+ }
+
+ throw new InvalidCursorPositionException();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close() throws Exception
+ {
+
+ super.close();
+
+ IndexCursor<V,E,ID> cursor;
+ int idx;
+
+ for ( idx = 0; idx < cursors.size(); idx++ )
+ {
+ cursor = cursors.get( idx );
+ if ( cursor != null )
+ {
+ cursor.close();
+ }
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close( Exception cause ) throws Exception
+ {
+ super.close( cause );
+
+ IndexCursor<V,E,ID> cursor;
+ int idx;
+
+ for ( idx = 0; idx < cursors.size(); idx++ )
+ {
+ cursor = cursors.get( idx );
+ if ( cursor != null )
+ {
+ cursor.close( cause );
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected String getUnsupportedMessage()
+ {
+ return UNSUPPORTED_MSG;
+ }
+
+
+ private void recomputeMinimum() throws Exception
+ {
+ IndexCursor<V,E,ID> cursor;
+ IndexEntry<V,ID> minValue;
+ IndexEntry<V,ID> value;
+ int idx;
+
+ cursor = cursors.get( getIndex );
+ if ( cursor.next() )
+ {
+ values.set( getIndex , cursor.get() );
+ }
+ else
+ {
+ values.set( getIndex, null );
+ }
+
+
+ minValue = null;
+ getIndex = -1;
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ value = values.get( idx );
+ if ( value != null )
+ {
+ if ( ( getIndex < 0 ) || ( comparator.compare( value, minValue ) < 0 ) )
+ {
+ minValue = value;
+ getIndex = idx;
+ }
+ }
+ }
+ }
+
+ private void recomputeMaximum() throws Exception
+ {
+ IndexCursor<V,E,ID> cursor;
+ IndexEntry<V,ID> maxValue;
+ IndexEntry<V,ID> value;
+ int idx;
+
+ cursor = cursors.get( getIndex );
+ if ( cursor.next() )
+ {
+ values.set( getIndex , cursor.get() );
+ }
+ else
+ {
+ values.set( getIndex, null );
+ }
+
+
+ maxValue = null;
+ getIndex = -1;
+ for ( idx = 0; idx < values.size(); idx++ )
+ {
+ value = values.get( idx );
+ if ( value != null )
+ {
+ if ( ( getIndex < 0 ) || ( comparator.compare( value, maxValue ) > 0 ) )
+ {
+ maxValue = value;
+ getIndex = idx;
+ }
+ }
+ }
+ }
+
+}
Added: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/MasterTableWrapper.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/MasterTableWrapper.java?rev=1185638&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/MasterTableWrapper.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/MasterTableWrapper.java Tue Oct 18 13:11:42 2011
@@ -0,0 +1,311 @@
+
+package org.apache.directory.server.core.txn;
+
+import java.util.Comparator;
+
+import org.apache.directory.server.core.partition.index.MasterTable;
+import org.apache.directory.shared.ldap.model.cursor.Cursor;
+import org.apache.directory.shared.ldap.model.cursor.Tuple;
+
+import org.apache.directory.shared.ldap.model.entry.Entry;
+
+public class MasterTableWrapper<ID, Entry> implements MasterTable<ID, Entry>
+{
+ private MasterTable<ID, Entry> wrappedTable;
+
+ /**
+ * {@inheritDoc}
+ */
+ public ID getNextId( Entry entry ) throws Exception
+ {
+ return wrappedTable.getNextId( entry );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void resetCounter() throws Exception
+ {
+ wrappedTable.resetCounter();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Comparator<ID> getKeyComparator()
+ {
+ return wrappedTable.getKeyComparator();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Comparator<Entry> getValueComparator()
+ {
+ return wrappedTable.getValueComparator();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName()
+ {
+ return wrappedTable.getName();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isDupsEnabled()
+ {
+ return wrappedTable.isDupsEnabled();
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Simple Table Key/Value Assertions
+ // ------------------------------------------------------------------------
+
+ /**
+ * Checks to see if this table has one or more tuples with a specific key:
+ * this is exactly the same as a get call with a check to see if the
+ * returned value is null or not.
+ *
+ * @param key the Object of the key to check for
+ * @return true if the key exists, false otherwise
+ * @throws Exception if there is a failure to read the underlying Db
+ */
+ boolean has( K key ) throws Exception;
+
+
+ /**
+ * Checks to see if this table has a key with a specific value.
+ *
+ * @param key the key to check for
+ * @param value the value to check for
+ * @return true if a record with the key and value exists, false otherwise
+ * @throws Exception if there is a failure to read the underlying Db
+ */
+ boolean has( K key, V value ) throws Exception;
+
+
+ /**
+ * Checks to see if this table has a record with a key greater than or
+ * equal to the key argument. The key argument need not exist for this
+ * call to return true. The underlying database must sort keys based on a
+ * key comparator because this method depends on key ordering.
+ *
+ * @param key the key to compare keys to
+ * @return true if a Tuple with a key greater than or equal to the key
+ * argument exists, false otherwise
+ * @throws Exception if there is a failure to read the underlying Db
+ */
+ boolean hasGreaterOrEqual( K key ) throws Exception;
+
+
+ /**
+ * Checks to see if this table has a record with a key less than or
+ * equal to the key argument. The key argument need not exist for this
+ * call to return true. The underlying database must sort keys based on a
+ * key comparator because this method depends on key ordering.
+ *
+ * @param key the key to compare keys to
+ * @return true if a Tuple with a key less than or equal to the key
+ * argument exists, false otherwise
+ * @throws Exception if there is a failure to read the underlying Db
+ */
+ boolean hasLessOrEqual( K key ) throws Exception;
+
+
+ /**
+ * Checks to see if this table has a Tuple with a key equal to the key
+ * argument, yet with a value greater than or equal to the value argument
+ * provided. The key argument <strong>MUST</strong> exist for this call
+ * to return true and the underlying Db must allow for values of duplicate
+ * keys to be sorted. The entire basis to this method depends on the fact
+ * that tuples of the same key have values sorted according to a valid
+ * value comparator.
+ *
+ * If the table does not support duplicates then an
+ * UnsupportedOperationException is thrown.
+ *
+ * @param key the key
+ * @param val the value to compare values to
+ * @return true if a Tuple with a key equal to the key argument and a
+ * value greater than the value argument exists, false otherwise
+ * @throws Exception if there is a failure to read the underlying Db
+ * or if the underlying Db is not of the Btree type that allows sorted
+ * duplicate values.
+ */
+ boolean hasGreaterOrEqual( K key, V val ) throws Exception;
+
+
+ /**
+ * Checks to see if this table has a Tuple with a key equal to the key
+ * argument, yet with a value less than or equal to the value argument
+ * provided. The key argument <strong>MUST</strong> exist for this call
+ * to return true and the underlying Db must allow for values of duplicate
+ * keys to be sorted. The entire basis to this method depends on the fact
+ * that tuples of the same key have values sorted according to a valid
+ * value comparator.
+ *
+ * If the table does not support duplicates then an
+ * UnsupportedOperationException is thrown.
+ *
+ * @param key the key
+ * @param val the value to compare values to
+ * @return true if a Tuple with a key equal to the key argument and a
+ * value less than the value argument exists, false otherwise
+ * @throws Exception if there is a failure to read the underlying Db
+ * or if the underlying Db is not of the Btree type that allows sorted
+ * duplicate values.
+ */
+ boolean hasLessOrEqual( K key, V val ) throws Exception;
+
+
+ /**
+ * {@inheritDoc}
+ */
+ Entry get( ID key ) throws Exception
+ {
+ Entry entry = wrappedTable.get( key );
+ }
+
+
+ /**
+ * Puts a record into this Table. Null is not allowed for keys or values
+ * and should result in an IllegalArgumentException.
+ *
+ * @param key the key of the record
+ * @param value the value of the record.
+ * @throws Exception if there is a failure to read or write to the
+ * underlying Db
+ * @throws IllegalArgumentException if a null key or value is used
+ */
+ void put( K key, V value ) throws Exception;
+
+
+ /**
+ * Removes all records with a specified key from this Table.
+ *
+ * @param key the key of the records to remove
+ * @throws Exception if there is a failure to read or write to
+ * the underlying Db
+ */
+ void remove( K key ) throws Exception;
+
+
+ /**
+ * Removes a single key value pair with a specified key and value from
+ * this Table.
+ *
+ * @param key the key of the record to remove
+ * @param value the value of the record to remove
+ * @throws Exception if there is a failure to read or write to
+ * the underlying Db
+ */
+ void remove( K key, V value ) throws Exception;
+
+
+ /**
+ * Creates a Cursor that traverses Tuples in a Table.
+ *
+ * @return a Cursor over Tuples containing the key value pairs
+ * @throws Exception if there are failures accessing underlying stores
+ */
+ Cursor<Tuple<K, V>> cursor() throws Exception;
+
+
+ /**
+ * Creates a Cursor that traverses Table Tuples for the same key. Only
+ * Tuples with the provided key will be returned if the key exists at
+ * all. If the key does not exist an empty Cursor is returned. The
+ * motivation behind this method is to minimize the need for callers to
+ * actively constrain Cursor operations based on the Tuples they return
+ * to a specific key. This Cursor is naturally limited to return only
+ * the tuples for the same key.
+ *
+ * @param key the duplicate key to return the Tuples of
+ * @return a Cursor over Tuples containing the same key
+ * @throws Exception if there are failures accessing underlying stores
+ */
+ Cursor<Tuple<K, V>> cursor( K key ) throws Exception;
+
+
+ /**
+ * Creates a Cursor that traverses Table values for the same key. Only
+ * Tuples with the provided key will have their values returned if the key
+ * exists at all. If the key does not exist an empty Cursor is returned.
+ * The motivation behind this method is to minimize the need for callers
+ * to actively constrain Cursor operations to a specific key while
+ * removing overheads in creating new Tuples or population one that is
+ * reused to return key value pairs. This Cursor is naturally limited to
+ * return only the values for the same key.
+ *
+ * @param key the duplicate key to return the values of
+ * @return a Cursor over values of a key
+ * @throws Exception if there are failures accessing underlying stores
+ */
+ Cursor<V> valueCursor( K key ) throws Exception;
+
+
+ // ------------------------------------------------------------------------
+ // Table Record Count Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Gets the count of the number of records in this Table.
+ *
+ * @return the number of records
+ * @throws Exception if there is a failure to read the underlying Db
+ */
+ int count() throws Exception;
+
+
+ /**
+ * Gets the count of the number of records in this Table with a specific
+ * key: returns the number of duplicates for a key.
+ *
+ * @param key the Object key to count.
+ * @return the number of duplicate records for a key.
+ * @throws Exception if there is a failure to read the underlying Db
+ */
+ int count( K key ) throws Exception;
+
+
+ /**
+ * Gets the number of records greater than or equal to a key value. The
+ * specific key argument provided need not exist for this call to return
+ * a non-zero value.
+ *
+ * @param key the key to use in comparisons
+ * @return the number of keys greater than or equal to the key
+ * @throws Exception if there is a failure to read the underlying db
+ */
+ int greaterThanCount( K key ) throws Exception;
+
+
+ /**
+ * Gets the number of records less than or equal to a key value. The
+ * specific key argument provided need not exist for this call to return
+ * a non-zero value.
+ *
+ * @param key the key to use in comparisons
+ * @return the number of keys less than or equal to the key
+ * @throws Exception if there is a failure to read the underlying db
+ */
+ int lessThanCount( K key ) throws Exception;
+
+
+ /**
+ * Closes the underlying Db of this Table.
+ *
+ * @throws Exception on any failures
+ */
+ void close() throws Exception;
+
+}
Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadOnlyTxn.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadOnlyTxn.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadOnlyTxn.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/ReadOnlyTxn.java Tue Oct 18 13:11:42 2011
@@ -1,7 +1,7 @@
package org.apache.directory.server.core.txn;
-public class ReadOnlyTxn extends AbstractTransaction
+class ReadOnlyTxn<ID> extends AbstractTransaction<ID>
{
}
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=1185638&r1=1185637&r2=1185638&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 Oct 18 13:11:42 2011
@@ -3,17 +3,41 @@ package org.apache.directory.server.core
import java.util.List;
import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.TreeSet;
+import java.util.Map;
+import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.Comparator;
import org.apache.directory.server.core.txn.logedit.LogEdit;
+import org.apache.directory.server.core.txn.logedit.IndexChange;
+import org.apache.directory.server.core.txn.logedit.DataChange;
+import org.apache.directory.server.core.txn.logedit.EntryAddDelete;
+import org.apache.directory.server.core.txn.logedit.EntryChange;
+import org.apache.directory.server.core.txn.logedit.DataChangeContainer;
import org.apache.directory.server.core.log.UserLogRecord;
-public class ReadWriteTxn extends AbstractTransaction
+import org.apache.directory.server.core.partition.index.ForwardIndexEntry;
+import org.apache.directory.server.core.partition.index.IndexEntry;
+import org.apache.directory.server.core.partition.index.Index;
+import org.apache.directory.server.core.partition.index.Serializer;
+
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.entry.AttributeUtils;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.Value;
+
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+
+class ReadWriteTxn<ID> extends AbstractTransaction<ID>
{
/** list of log edits by the txn */
- List<LogEdit> logEdits = new LinkedList<LogEdit>();
+ private List<LogEdit<ID>> logEdits = new LinkedList<LogEdit<ID>>();
/*
* Number of txns that depend on this txn and previous committed
@@ -22,14 +46,19 @@ public class ReadWriteTxn extends Abstra
* committed and ref count becomes zero for all the previously
* committed txns.
*/
- AtomicInteger txnRefCount = new AtomicInteger( 0 );
+ private AtomicInteger txnRefCount = new AtomicInteger( 0 );
/** User record used to communicate data with log manager */
- UserLogRecord logRecord = new UserLogRecord();
+ private UserLogRecord logRecord = new UserLogRecord();
+
+ private Map<Dn, Map<String, TreeSet< IndexEntry<Object,ID> >>> forwardIndexAdds =
+ new HashMap<Dn, Map<String, TreeSet< IndexEntry<Object,ID> >>>();
- // TODO add a map of index changes
-
+ private Map<Dn, Map<String, TreeSet< IndexEntry<Object,ID> >>> reverseIndexAdds =
+ new HashMap<Dn, Map<String, TreeSet< IndexEntry<Object,ID> >>>();
+ private Map<Dn, Map<String, TreeSet< IndexEntry<Object,ID> >>> indexDeletes =
+ new HashMap<Dn, Map<String, TreeSet< IndexEntry<Object,ID> >>>();
public AtomicInteger getRefCount()
{
@@ -38,13 +67,227 @@ public class ReadWriteTxn extends Abstra
public UserLogRecord getUserLogRecord()
{
- return this.getUserLogRecord();
+ return logRecord;
}
- public List<LogEdit> getEdits()
+ public List<LogEdit<ID>> getEdits()
{
return logEdits;
}
+ @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();
+ 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 =
+ forwardIndexAdds.get( partitionDn );
+
+ Map<String, TreeSet<IndexEntry<Object,ID>>> reverseIndices =
+ reverseIndexAdds.get( partitionDn );
+
+ if ( forwardIndices == null )
+ {
+ forwardIndices = new HashMap<String, TreeSet<IndexEntry<Object,ID>>>();
+
+ // Reverse index changes should be null too
+ 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 );
+
+ if ( deletedIndices == null )
+ {
+ 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;
+ indexChangeType = indexChange.getType();
+ Index<Object,?,ID> index = (Index<Object,?,ID>)indexChange.getIndex();
+
+ TreeSet<IndexEntry<Object,ID>> forwardAdds =
+ forwardIndices.get( indexChange.getOID() );
+
+ TreeSet<IndexEntry<Object,ID>> reverseAdds =
+ reverseIndices.get( indexChange.getOID() );
+
+ if ( forwardAdds == null )
+ {
+ forwardAdds =
+ new TreeSet<IndexEntry<Object, ID>>( index.getForwardIndexEntryComparator() );
+ 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() );
+ if ( deletes == null )
+ {
+ deletes = new TreeSet<IndexEntry<Object,ID>>( index.getForwardIndexEntryComparator() );
+ deletedIndices.put( indexChange.getOID(), deletes );
+ }
+
+
+ indexEntry = new ForwardIndexEntry<Object,ID>();
+ indexEntry.setValue( indexChange.getKey() );
+ indexEntry.setId( indexChange.getID() );
+
+ if ( indexChangeType == IndexChange.Type.ADD )
+ {
+ deletes.remove( indexEntry );
+ forwardAdds.add( indexEntry );
+ reverseAdds.add( indexEntry );
+ }
+ else
+ {
+ deletes.add( indexEntry );
+ forwardAdds.remove( indexEntry );
+ reverseAdds.remove( indexEntry );
+ }
+ }
+ }
+
+ }
+ }
+
+ public Entry applyUpdatesToEntry( Dn partitionDn, ID entryID, Entry curEntry, boolean cloneOnChange )
+ {
+ boolean needToCloneOnChange = cloneOnChange;
+ LogEdit<ID> edit;
+ DataChangeContainer<ID> container;
+
+ Iterator<LogEdit<ID>> it = logEdits.iterator();
+
+ while ( it.hasNext() )
+ {
+ edit = it.next();
+
+ if ( edit instanceof DataChangeContainer )
+ {
+ container = (DataChangeContainer<ID>)edit;
+
+ /**
+ * Check if the container has changes for the entry
+ * and the version says we need to apply this change
+ */
+ //TODO check version and id here. If uuid is not available,
+ // then match partitionDn as well.
+ String uuid = container.getUUID();
+ boolean applyChanges = false;
+
+ if ( uuid != null )
+ {
+ /*
+ * Container has changes for entry. Check if the entry change
+ * affects out entry by comparing uuid if entry is available.
+ * Otherwise compare partition dn and Id.
+ */
+
+ if ( curEntry!= null )
+ {
+ String curUuid = null;
+ try
+ {
+ curUuid = curEntry.get( SchemaConstants.ENTRY_UUID_AT ).getString();
+ if ( curUuid.equals( uuid ) )
+ {
+ //TODO check the version here to see if the change should be applied
+ }
+ }
+ catch( LdapException e )
+ {
+ //TODO decide whether to throw IOException or an internal exception here
+ }
+ }
+ else
+ {
+ Comparator<ID> idComp = TxnManagerFactory.<ID>txnManagerInstance().getIDComparator();
+ if ( partitionDn.equals( container.getPartitionDn() ) && ( idComp.compare( entryID, container.getEntryID() ) == 0 ))
+ {
+ applyChanges = true;
+ }
+ }
+
+ }
+
+ if ( applyChanges )
+ {
+ List<DataChange<ID>> dataChanges = container.getChanges();
+ Iterator<DataChange<ID>> dit = dataChanges.iterator();
+ DataChange<ID> nextChange;
+
+ while ( dit.hasNext() )
+ {
+ nextChange = dit.next();
+ if ( nextChange instanceof EntryChange && ( curEntry != null ) )
+ {
+ EntryChange<ID> entryChange = (EntryChange<ID>)nextChange;
+
+ if ( needToCloneOnChange )
+ {
+ curEntry = curEntry.clone();
+ needToCloneOnChange = false;
+ }
+
+
+ try
+ {
+ AttributeUtils.applyModification(curEntry, entryChange.getRedoChange());
+ }
+ catch( LdapException e )
+ {
+ //TODO decide whether to throw IOException or an internal exception here
+ }
+ }
+ else if ( nextChange instanceof EntryAddDelete )
+ {
+ EntryAddDelete<ID> addDelete = (EntryAddDelete<ID>)nextChange;
+ needToCloneOnChange = false;
+
+ if ( addDelete.getType() == EntryAddDelete.Type.ADD )
+ {
+ curEntry = addDelete.getChangedEntry();
+ }
+ else
+ {
+ curEntry = null;
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ return curEntry;
+
+ }
}
Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/Transaction.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/Transaction.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/Transaction.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/Transaction.java Tue Oct 18 13:11:42 2011
@@ -3,10 +3,13 @@ package org.apache.directory.server.core
import java.util.List;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.name.Dn;
-interface Transaction
+
+interface Transaction<ID>
{
- public List<ReadWriteTxn> getTxnsToCheck();
+ public List<ReadWriteTxn<ID>> getTxnsToCheck();
public long getStartTime();
@@ -18,8 +21,9 @@ interface Transaction
public void abortTxn();
- public State getState();
+ public State getState();
+ public Entry mergeUpdates( Dn partitionDn, ID entryID, Entry entry );
enum State
{
Added: 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=1185638&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnIndexCursor.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnIndexCursor.java Tue Oct 18 13:11:42 2011
@@ -0,0 +1,252 @@
+
+package org.apache.directory.server.core.txn;
+
+import org.apache.directory.server.core.partition.index.IndexCursor;
+import org.apache.directory.server.core.partition.index.AbstractIndexCursor;
+import org.apache.directory.server.core.partition.index.IndexEntry;
+
+import org.apache.directory.server.core.partition.index.ForwardIndexEntry;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.shared.ldap.model.cursor.InvalidCursorPositionException;
+import org.apache.directory.shared.ldap.model.cursor.Tuple;
+
+import java.util.Iterator;
+import java.util.SortedSet;
+import java.util.NavigableSet;
+
+public class TxnIndexCursor <V, O, ID> extends AbstractIndexCursor<V, O, ID>
+{
+ /** list of changed index entries */
+ private NavigableSet<IndexEntry<V,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<V,ID>> it;
+
+ /** currently available value */
+ IndexEntry<V,ID> availableValue;
+
+ /** unsupported operation message */
+ private static final String UNSUPPORTED_MSG = I18n.err( I18n.ERR_722 );
+
+
+ public TxnIndexCursor( NavigableSet<IndexEntry<V,ID>> changedEntries, boolean forwardIndex )
+ {
+ this.changedEntries = changedEntries;
+ this.forwardIndex = forwardIndex;
+
+ if ( changedEntries.size() < 1 )
+ {
+ throw new IllegalArgumentException("TxnIndexCursor should not be constructed with no index changes");
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void after( IndexEntry<V, ID> element ) throws Exception
+ {
+ positioned = true;
+ availableValue = null;
+ movingNext = true;
+ it = changedEntries.tailSet( element, false ).iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void before( IndexEntry<V, ID> element ) throws Exception
+ {
+ positioned = true;
+ availableValue = null;
+ movingNext = true;
+ it = changedEntries.tailSet( element, true ).iterator();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterValue( ID id, V value ) throws Exception
+ {
+ ForwardIndexEntry<V,ID> indexEntry = new ForwardIndexEntry();
+ indexEntry.setId( id );
+ indexEntry.setValue( value );
+ this.after( indexEntry );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeValue( ID id, V value ) throws Exception
+ {
+ ForwardIndexEntry<V,ID> indexEntry = new ForwardIndexEntry();
+ indexEntry.setId( id );
+ indexEntry.setValue( value );
+ this.before( indexEntry );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeFirst() throws Exception
+ {
+ positioned = true;
+ availableValue = null;
+ movingNext = true;
+ it = changedEntries.iterator();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterLast() throws Exception
+ {
+ positioned = true;
+ availableValue = null;
+ movingNext = false;
+ it = changedEntries.descendingIterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean first() throws Exception
+ {
+ this.beforeFirst();
+ return this.next();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean last() throws Exception
+ {
+ this.afterLast();
+ return this.previous();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean previous() throws Exception
+ {
+ if ( positioned == false )
+ {
+ afterLast();
+ }
+
+ if ( movingNext == true )
+ {
+ if ( availableValue == null )
+ {
+ if ( it.hasNext() )
+ {
+ availableValue = it.next();
+ }
+ }
+
+ if ( availableValue == null )
+ {
+ it = changedEntries.descendingIterator();
+ }
+ else
+ {
+ it = changedEntries.headSet( availableValue, false ).descendingIterator();
+ }
+
+ availableValue = null;
+ movingNext = false;
+ }
+
+ if ( it.hasNext() )
+ {
+ availableValue = it.next();
+ return true;
+ }
+ else
+ {
+ availableValue = null;
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean next() throws Exception
+ {
+ if ( positioned == false )
+ {
+ afterLast();
+ }
+
+ if ( movingNext == false )
+ {
+ if ( availableValue == null )
+ {
+ if ( it.hasNext() )
+ {
+ availableValue = it.next();
+ }
+ }
+
+ if ( availableValue == null )
+ {
+ it = changedEntries.iterator();
+ }
+ else
+ {
+ it = changedEntries.tailSet( availableValue, false ).descendingIterator();
+ }
+
+ availableValue = null;
+ movingNext = true;
+ }
+
+ if ( it.hasNext() )
+ {
+ availableValue = it.next();
+ return true;
+ }
+ else
+ {
+ availableValue = null;
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IndexEntry<V, ID> get() throws Exception
+ {
+ if ( availableValue != null )
+ {
+ return availableValue;
+ }
+
+ throw new InvalidCursorPositionException();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected String getUnsupportedMessage()
+ {
+ return UNSUPPORTED_MSG;
+ }
+
+}
Added: 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=1185638&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerFactory.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerFactory.java Tue Oct 18 13:11:42 2011
@@ -0,0 +1,40 @@
+
+package org.apache.directory.server.core.txn;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import org.apache.directory.server.core.partition.index.Serializer;
+
+public class TxnManagerFactory
+{
+ private static TxnManager<?> txnManager;
+
+ private static TxnLogManager<?> txnLogManager;
+
+ public static <ID> void
+ init(Comparator<ID> idComparator, Serializer idSerializer)
+ {
+ 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
+
+ dTxnManager.init( dTxnLogManager, idComparator, idSerializer );
+ }
+
+
+ public static <ID> TxnManager<ID> txnManagerInstance()
+ {
+ return ( (TxnManager<ID>) txnManager );
+ }
+
+ public static <ID> TxnLogManager<ID> txnLogManagerInstance()
+ {
+ return ( (TxnLogManager<ID>) txnLogManager );
+ }
+}
Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerInternal.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerInternal.java?rev=1185638&r1=1185637&r2=1185638&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerInternal.java (original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/TxnManagerInternal.java Tue Oct 18 13:11:42 2011
@@ -1,7 +1,7 @@
package org.apache.directory.server.core.txn;
-public interface TxnManagerInternal extends TxnManager
+public interface TxnManagerInternal<ID> extends TxnManager<ID>
{
- public Transaction getCurTxn();
+ public Transaction<ID> getCurTxn();
}
Added: 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=1185638&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/DataChangeContainer.java (added)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/txn/logedit/DataChangeContainer.java Tue Oct 18 13:11:42 2011
@@ -0,0 +1,162 @@
+
+package org.apache.directory.server.core.txn.logedit;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+import org.apache.directory.server.core.log.LogAnchor;
+
+import org.apache.directory.shared.ldap.model.name.Dn;
+
+import org.apache.directory.server.core.partition.index.Serializer;
+
+import org.apache.directory.server.core.txn.TxnManagerFactory;
+
+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)
+ {
+ this.partitionDn = partitionDn;
+ this.txnID = txnID;
+ }
+
+ public String getUUID()
+ {
+ return uuid;
+ }
+
+ public void setUUID( String entryUUID )
+ {
+ this.uuid = entryUUID;
+ }
+
+ public long getTxnID()
+ {
+ return this.txnID;
+ }
+
+ public Dn getPartitionDn()
+ {
+ return partitionDn;
+ }
+
+ public ID getEntryID()
+ {
+ return entryID;
+ }
+
+ 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();
+ if ( len < 0 )
+ {
+ entryID = null;
+ }
+ else
+ {
+ byte[] buf = new byte[len];
+ in.readFully( 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();
+ changes.add( change );
+ }
+ }
+
+
+ @Override
+ public void writeExternal( ObjectOutput out ) throws IOException
+ {
+ Serializer idSerializer = TxnManagerFactory.txnManagerInstance().getIDSerializer();
+ DataChange<ID> change;
+
+
+ if ( uuid != null )
+ {
+ out.writeBoolean( true );
+ out.writeUTF( uuid );
+ }
+ else
+ {
+ out.writeBoolean( false );
+ }
+
+ if ( entryID == null )
+ {
+ out.writeInt( -1 );
+ }
+ else
+ {
+ byte[] buf = idSerializer.serialize( entryID );
+ 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() )
+ {
+ change = it.next();
+ change.writeExternal( out );
+ }
+ }
+
+}