Merged HEAD-BUG-FIX (4.3/Cloud) to HEAD (4.3/Cloud)

59123: Merged V4.2-BUG-FIX (4.2.1) to HEAD-BUG-FIX (Cloud/4.3)
      59111: Merged V4.1-BUG-FIX (4.1.8) to V4.2-BUG-FIX (4.2.1)
         59070: Merged DEV to V4.1-BUG-FIX (4.1.8)
            58849: MNT-10096: MT: AbstractTenantRoutingContentStore can return null list of stores
              - Ensure that RetryingTransactionHelper starts a transaction in txn-after-completion phase (MNT-9806).


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@62103 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2014-02-12 01:06:17 +00:00
parent 68bfd2b72e
commit 8a8cf1b81a
3 changed files with 67 additions and 15 deletions

View File

@@ -366,8 +366,7 @@ public class RetryingTransactionHelper
} }
// First validate the requiresNew setting // First validate the requiresNew setting
boolean startingNew = requiresNew; if (!requiresNew)
if (!startingNew)
{ {
TxnReadState readState = AlfrescoTransactionSupport.getTransactionReadState(); TxnReadState readState = AlfrescoTransactionSupport.getTransactionReadState();
switch (readState) switch (readState)
@@ -385,7 +384,7 @@ public class RetryingTransactionHelper
break; break;
case TXN_NONE: case TXN_NONE:
// There is no current transaction so we need a new one. // There is no current transaction so we need a new one.
startingNew = true; requiresNew = true;
break; break;
default: default:
throw new RuntimeException("Unknown transaction state: " + readState); throw new RuntimeException("Unknown transaction state: " + readState);
@@ -395,7 +394,7 @@ public class RetryingTransactionHelper
// If we are time limiting, set ourselves a time limit and maintain the count of concurrent transactions // If we are time limiting, set ourselves a time limit and maintain the count of concurrent transactions
long startTime = 0; long startTime = 0;
Throwable stackTrace = null; Throwable stackTrace = null;
if (startingNew && maxExecutionMs > 0) if (requiresNew && maxExecutionMs > 0)
{ {
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
synchronized (this) synchronized (this)
@@ -433,11 +432,10 @@ public class RetryingTransactionHelper
UserTransaction txn = null; UserTransaction txn = null;
try try
{ {
if (startingNew) if (requiresNew)
{ {
txn = requiresNew ? txn = txnService.getNonPropagatingUserTransaction(readOnly, forceWritable);
txnService.getNonPropagatingUserTransaction(readOnly, forceWritable) :
txnService.getUserTransaction(readOnly, forceWritable);
txn.begin(); txn.begin();
// Wrap it to protect it // Wrap it to protect it
UserTransactionProtectionAdvise advise = new UserTransactionProtectionAdvise(); UserTransactionProtectionAdvise advise = new UserTransactionProtectionAdvise();
@@ -588,7 +586,7 @@ public class RetryingTransactionHelper
} }
finally finally
{ {
if (startingNew && maxExecutionMs > 0) if (requiresNew && maxExecutionMs > 0)
{ {
synchronized (this) synchronized (this)
{ {

View File

@@ -246,6 +246,12 @@ public class AlfrescoTransactionSupportTest extends TestCase
{ {
postCommitReadState[0] = AlfrescoTransactionSupport.getTransactionReadState(); postCommitReadState[0] = AlfrescoTransactionSupport.getTransactionReadState();
} }
@Override
public void afterRollback()
{
postCommitReadState[0] = AlfrescoTransactionSupport.getTransactionReadState();
}
}; };
RetryingTransactionCallback<TxnReadState> getReadStateWork = new RetryingTransactionCallback<TxnReadState>() RetryingTransactionCallback<TxnReadState> getReadStateWork = new RetryingTransactionCallback<TxnReadState>()
@@ -271,6 +277,20 @@ public class AlfrescoTransactionSupportTest extends TestCase
checkTxnReadState = transactionService.getRetryingTransactionHelper().doInTransaction(getReadStateWork, false); checkTxnReadState = transactionService.getRetryingTransactionHelper().doInTransaction(getReadStateWork, false);
assertEquals("Expected 'read-write transaction'", TxnReadState.TXN_READ_WRITE, checkTxnReadState); assertEquals("Expected 'read-write transaction'", TxnReadState.TXN_READ_WRITE, checkTxnReadState);
assertEquals("Expected 'no transaction'", TxnReadState.TXN_NONE, postCommitReadState[0]); assertEquals("Expected 'no transaction'", TxnReadState.TXN_NONE, postCommitReadState[0]);
// Check TXN_NONE on rollback
UserTransaction txn = transactionService.getUserTransaction();
txn.begin();
AlfrescoTransactionSupport.bindListener(getReadStatePostCommit);
txn.rollback();
assertEquals("Expected 'no transaction'", TxnReadState.TXN_NONE, postCommitReadState[0]);
// Check TXN_NONE on commit
txn = transactionService.getUserTransaction();
txn.begin();
AlfrescoTransactionSupport.bindListener(getReadStatePostCommit);
txn.commit();
assertEquals("Expected 'no transaction'", TxnReadState.TXN_NONE, postCommitReadState[0]);
} }
public void testResourceHelper() throws Exception public void testResourceHelper() throws Exception

View File

@@ -334,7 +334,7 @@ public class RetryingTransactionHelperTest extends TestCase
/** /**
* Checks nesting of two transactions with <code>requiresNew == false</code> * Checks nesting of two transactions with <code>requiresNew == false</code>
*/ */
public void testNestedWithPropogation() public void testNestedWithPropagation()
{ {
RetryingTransactionCallback<Long> callback = new RetryingTransactionCallback<Long>() RetryingTransactionCallback<Long> callback = new RetryingTransactionCallback<Long>()
{ {
@@ -362,7 +362,7 @@ public class RetryingTransactionHelperTest extends TestCase
/** /**
* Checks nesting of two transactions with <code>requiresNew == true</code> * Checks nesting of two transactions with <code>requiresNew == true</code>
*/ */
public void testNestedWithoutPropogation() public void testNestedWithoutPropagation()
{ {
RetryingTransactionCallback<Long> callback = new RetryingTransactionCallback<Long>() RetryingTransactionCallback<Long> callback = new RetryingTransactionCallback<Long>()
{ {
@@ -390,17 +390,18 @@ public class RetryingTransactionHelperTest extends TestCase
/** /**
* Checks nesting of two transactions with <code>requiresNew == true</code>, * Checks nesting of two transactions with <code>requiresNew == true</code>,
* but where the two transactions get involved in a concurrency struggle. * but where the two transactions get involved in a concurrency struggle.
* * <p/>
* Note: skip test for non-MySQL * Note: skip test for non-MySQL
*/ */
public void testNestedWithoutPropogationConcurrentUntilFailureMySQL() throws InterruptedException public void testNestedWithoutPropagationConcurrentUntilFailureMySQL() throws InterruptedException
{ {
final RetryingTransactionHelper txnHelperForTest = transactionService.getRetryingTransactionHelper(); final RetryingTransactionHelper txnHelperForTest = transactionService.getRetryingTransactionHelper();
txnHelperForTest.setMaxRetries(1); txnHelperForTest.setMaxRetries(1);
if (! (dialect instanceof MySQLInnoDBDialect)) if (! (dialect instanceof MySQLInnoDBDialect))
{ {
// NOOP - skip test for non-MySQL DB dialects to avoid hang if concurrently "nested" (in terms of Spring) since the initial transaction does not complete // NOOP - skip test for non-MySQL DB dialects to avoid hang if concurrently "nested" (in terms of Spring)
// since the initial transaction does not complete
// see testConcurrencyRetryingNoFailure instead // see testConcurrencyRetryingNoFailure instead
logger.warn("NOTE: Skipping testNestedWithoutPropogationConcurrentUntilFailureMySQLOnly for dialect: "+dialect); logger.warn("NOTE: Skipping testNestedWithoutPropogationConcurrentUntilFailureMySQLOnly for dialect: "+dialect);
} }
@@ -556,6 +557,7 @@ public class RetryingTransactionHelperTest extends TestCase
assertEquals("Should have been called exactly once", 1, callCount.intValue()); assertEquals("Should have been called exactly once", 1, callCount.intValue());
} }
@SuppressWarnings({ "unchecked", "rawtypes" })
public void testTimeLimit() public void testTimeLimit()
{ {
final RetryingTransactionHelper txnHelper = new RetryingTransactionHelper(); final RetryingTransactionHelper txnHelper = new RetryingTransactionHelper();
@@ -617,7 +619,39 @@ public class RetryingTransactionHelperTest extends TestCase
assertEquals("Should have been called tree times", 3, callCount.intValue()); assertEquals("Should have been called tree times", 3, callCount.intValue());
} }
public void testStartNewTransaction() throws Exception
{
// MNT-10096
class CustomListenerAdapter extends TransactionListenerAdapter
{
private String newTxnId;
@Override
public void afterRollback()
{
newTxnId = txnHelper.doInTransaction(new RetryingTransactionCallback<String>()
{
@Override
public String execute() throws Throwable
{
return AlfrescoTransactionSupport.getTransactionId();
}
}, true, false);
}
}
UserTransaction txn = transactionService.getUserTransaction();
txn.begin();
String txnId = AlfrescoTransactionSupport.getTransactionId();
CustomListenerAdapter listener = new CustomListenerAdapter();
AlfrescoTransactionSupport.bindListener(listener);
txn.rollback();
assertFalse("New transaction has not started", txnId.equals(listener.newTxnId));
}
private void runThreads(final RetryingTransactionHelper txnHelper, final List<Throwable> caughtExceptions, private void runThreads(final RetryingTransactionHelper txnHelper, final List<Throwable> caughtExceptions,
Pair<Integer, Integer>... startDurationPairs) Pair<Integer, Integer>... startDurationPairs)
{ {