Author: saya
Date: Mon Mar 19 07:08:52 2012
New Revision: 1302302
URL: http://svn.apache.org/viewvc?rev=1302302&view=rev
Log:
First real end to end test to work the guts of txn system. The test has two threads to do
modify operations on the same attribute of the same entry . They conflict but the resulting
entry is a serialized form of their executions.
the rest is the fix based on this test.
next will come similar tests for other ldap operations.
Added:
directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/
directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java
Modified:
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractChangeOperationContext.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java
directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/OperationContext.java
directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockOperation.java
directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java
directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
directory/apacheds/branches/apacheds-txns/interceptors/changelog/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractChangeOperationContext.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractChangeOperationContext.java?rev=1302302&r1=1302301&r2=1302302&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractChangeOperationContext.java
(original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractChangeOperationContext.java
Mon Mar 19 07:08:52 2012
@@ -53,6 +53,20 @@ public abstract class AbstractChangeOper
public AbstractChangeOperationContext( CoreSession session )
{
super( session );
+
+ logChange = LogChange.TRUE;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void reset()
+ {
+ super.reset();
+ modifiedEntry = null;
+ logChange = LogChange.FALSE;
+ changeLogEvent = null;
}
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java?rev=1302302&r1=1302301&r2=1302302&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java
(original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java
Mon Mar 19 07:08:52 2012
@@ -89,6 +89,15 @@ public abstract class AbstractOperationC
this.session = session;
currentInterceptor = 0;
}
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void reset()
+ {
+ currentInterceptor = 0;
+ }
/**
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java?rev=1302302&r1=1302301&r2=1302302&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java
(original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.java
Mon Mar 19 07:08:52 2012
@@ -25,6 +25,7 @@ import java.util.List;
import org.apache.directory.server.core.api.CoreSession;
import org.apache.directory.server.core.api.OperationEnum;
+import org.apache.directory.server.core.api.changelog.LogChange;
import org.apache.directory.server.core.api.entry.ServerEntryUtils;
import org.apache.directory.shared.ldap.model.message.controls.ManageDsaIT;
import org.apache.directory.shared.ldap.model.entry.DefaultModification;
@@ -67,6 +68,16 @@ public class ModifyOperationContext exte
setInterceptors( session.getDirectoryService().getInterceptors( OperationEnum.MODIFY
) );
}
}
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void reset()
+ {
+ super.reset();
+ alteredEntry = null;
+ }
/**
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/OperationContext.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/OperationContext.java?rev=1302302&r1=1302301&r2=1302302&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/OperationContext.java
(original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/OperationContext.java
Mon Mar 19 07:08:52 2012
@@ -41,6 +41,13 @@ import org.apache.directory.shared.ldap.
public interface OperationContext
{
/**
+ * Called when operation is to be re-executed.Operation context willr reset its state
+ * related to the execution of the operation
+ */
+ void reset();
+
+
+ /**
* @return The number of the current interceptor in the list
*/
int getCurrentInterceptor();
Modified: directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockOperation.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockOperation.java?rev=1302302&r1=1302301&r2=1302302&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockOperation.java
(original)
+++ directory/apacheds/branches/apacheds-txns/core-api/src/test/java/org/apache/directory/server/core/api/MockOperation.java
Mon Mar 19 07:08:52 2012
@@ -48,6 +48,12 @@ public class MockOperation implements Op
this.session = new MockCoreSession( new LdapPrincipal( schemaManager, new Dn( schemaManager
), AuthenticationLevel.STRONG ),
new MockDirectoryService( count ) );
}
+
+
+ public void reset()
+ {
+
+ }
public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
Added: directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java?rev=1302302&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java
(added)
+++ directory/apacheds/branches/apacheds-txns/core-integ/src/test/java/org/apache/directory/server/core/txn/TxnConflictIT.java
Mon Mar 19 07:08:52 2012
@@ -0,0 +1,128 @@
+
+package org.apache.directory.server.core.txn;
+
+import static org.apache.directory.server.core.integ.IntegrationUtils.getSystemContext;
+
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.directory.server.core.annotations.ApplyLdifs;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.apache.directory.server.core.integ.IntegrationUtils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+@RunWith ( FrameworkRunner.class )
+@CreateDS(name = "TxnConflictIT")
+@ApplyLdifs(
+ {
+ "dn: cn=test1, ou=system",
+ "objectClass: top",
+ "objectClass: person",
+ "cn: test1",
+ "sn: Jim",
+ "description: useless guy"
+ }
+)
+
+
+public class TxnConflictIT extends AbstractLdapTestUnit
+{
+ enum ConflictType
+ {
+ MODIFY_MODIFY_CONLICT
+ }
+
+
+ @Test
+ public void testModifyModifyConflict() throws Exception
+ {
+ try
+ {
+ ConflictingThread cThread = new ConflictingThread( ConflictType.MODIFY_MODIFY_CONLICT
);
+
+ cThread.start();
+
+ LdapContext sysRoot = getSystemContext( getService() );
+
+ // The added value
+ Attributes attrs = new BasicAttributes( "telephoneNumber", "1 650 300 6089",
true );
+
+ // Add the Ava
+ sysRoot.modifyAttributes( "cn=test1", DirContext.ADD_ATTRIBUTE, attrs );
+
+ cThread.join();
+
+ // Entry should contain two telephone numbers now
+ attrs = sysRoot.getAttributes( "cn=test1" );
+ Attribute attr = attrs.get( "telephoneNumber" );
+ assertNotNull( attr );
+ assertEquals( 2, attr.size() );
+ assertTrue( attr.contains( "1 650 300 6089" ) );
+ assertTrue( attr.contains( "1 650 300 6088" ) );
+
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+
+ fail();
+ }
+
+
+ }
+
+ class ConflictingThread extends Thread
+ {
+ ConflictType type;
+
+ public ConflictingThread( ConflictType type )
+ {
+ this.type = type;
+ }
+
+ private void doConflictingModify() throws Exception
+ {
+ LdapContext sysRoot = getSystemContext( getService() );
+
+ // The added value
+ Attributes attrs = new BasicAttributes( "telephoneNumber", "1 650 300 6088",
true );
+
+ // Add the Ava
+ sysRoot.modifyAttributes( "cn=test1", DirContext.ADD_ATTRIBUTE, attrs );
+ }
+
+ public void run()
+ {
+ System.out.println("here1");
+ try
+ {
+ if (type == ConflictType.MODIFY_MODIFY_CONLICT )
+ {
+ this.doConflictingModify();
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+
+ fail();
+ }
+ }
+ }
+
+
+}
+
Modified: directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java?rev=1302302&r1=1302301&r2=1302302&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java
(original)
+++ directory/apacheds/branches/apacheds-txns/core-shared/src/main/java/org/apache/directory/server/core/shared/txn/DefaultTxnManager.java
Mon Mar 19 07:08:52 2012
@@ -193,7 +193,9 @@ class DefaultTxnManager implements TxnMa
// abort current txn and start a new read write txn
- abortTransaction();
+
+ abortReadWriteTxn( ( ReadWriteTxn ) curTxn );
+ curTxn.abortTxn();
return beginReadWriteTxn( true );
}
@@ -237,20 +239,36 @@ class DefaultTxnManager implements TxnMa
throw new IllegalStateException( " trying to commit non existent txn " );
}
- if ( flushFailed )
- {
- throw new IOException( "Flushing of txns failed" );
- }
-
- prepareForEndingTxn( txn );
+ boolean isExclusive = txn.isExclusive();
- if ( txn instanceof ReadOnlyTxn )
- {
- txn.commitTxn( txn.getStartTime() );
+ try
+ {
+ if ( flushFailed )
+ {
+ throw new IOException( "Flushing of txns failed" );
+ }
+
+ prepareForEndingTxn( txn );
+
+ if ( txn instanceof ReadOnlyTxn )
+ {
+ txn.commitTxn( txn.getStartTime() );
+ }
+ else
+ {
+ commitReadWriteTxn( ( ReadWriteTxn ) txn );
+ }
}
- else
+ finally
{
- commitReadWriteTxn( ( ReadWriteTxn ) txn );
+ if ( !isExclusive )
+ {
+ optimisticLock.readLock().unlock();
+ }
+ else
+ {
+ optimisticLock.writeLock().unlock();
+ }
}
setCurTxn( null );
@@ -392,6 +410,8 @@ class DefaultTxnManager implements TxnMa
ReadOnlyTxn txn = new ReadOnlyTxn();
ReadWriteTxn lastTxnToCheck = null;
+ optimisticLock.readLock().lock();
+
/*
* Set the start time as the latest committed txn's commit time. We need to make
sure that
* any change after our start time is not flushed to the partitions. Say we have
txn1 as the
@@ -420,7 +440,6 @@ class DefaultTxnManager implements TxnMa
buildCheckList( txn, lastTxnToCheck );
- optimisticLock.readLock().lock();
setCurTxn( txn );
//System.out.println( "TRAN: Started " + txn );
@@ -478,7 +497,6 @@ class DefaultTxnManager implements TxnMa
lastTxnToCheck = latestVerifiedTxn.get();
lastTxnToCheck.getRefCount().incrementAndGet();
-
}
while ( lastTxnToCheck != latestVerifiedTxn.get() );
}
@@ -586,7 +604,7 @@ class DefaultTxnManager implements TxnMa
throw new IllegalStateException( " prepareForEndingTxn: txn has unpexptected
start time " +
txn + " expected: " + lastTxnToCheck );
}
-
+
if ( lastTxnToCheck.getRefCount().get() <= 0 )
{
throw new IllegalStateException( " prepareForEndingTxn: lastTxnToCheck has
unexpected ref cnt " +
Modified: directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java?rev=1302302&r1=1302301&r2=1302302&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
(original)
+++ directory/apacheds/branches/apacheds-txns/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
Mon Mar 19 07:08:52 2012
@@ -998,6 +998,7 @@ public class DefaultOperationManager imp
{
if ( startedTxn )
{
+ modifyContext.reset();
retryTransactionRW( txnManager );
}
else if ( curTxn == null )
Modified: directory/apacheds/branches/apacheds-txns/interceptors/changelog/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/interceptors/changelog/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java?rev=1302302&r1=1302301&r2=1302302&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/interceptors/changelog/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
(original)
+++ directory/apacheds/branches/apacheds-txns/interceptors/changelog/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
Mon Mar 19 07:08:52 2012
@@ -220,6 +220,12 @@ public class ChangeLogInterceptor extend
// Call the next interceptor
next( modifyContext );
+
+ // If op doesnt want to be logged, skipped
+ if ( !modifyContext.isLogChange() )
+ {
+ return;
+ }
// @TODO: needs big consideration!!!
// NOTE: perhaps we need to log this as a system operation that cannot and should
not be reapplied?
|