diff --git a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java index a1893932e4..cd79b4eb6b 100644 --- a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java +++ b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java @@ -366,8 +366,7 @@ public class RetryingTransactionHelper } // First validate the requiresNew setting - boolean startingNew = requiresNew; - if (!startingNew) + if (!requiresNew) { TxnReadState readState = AlfrescoTransactionSupport.getTransactionReadState(); switch (readState) @@ -385,7 +384,7 @@ public class RetryingTransactionHelper break; case TXN_NONE: // There is no current transaction so we need a new one. - startingNew = true; + requiresNew = true; break; default: 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 long startTime = 0; Throwable stackTrace = null; - if (startingNew && maxExecutionMs > 0) + if (requiresNew && maxExecutionMs > 0) { startTime = System.currentTimeMillis(); synchronized (this) @@ -433,11 +432,10 @@ public class RetryingTransactionHelper UserTransaction txn = null; try { - if (startingNew) + if (requiresNew) { - txn = requiresNew ? - txnService.getNonPropagatingUserTransaction(readOnly, forceWritable) : - txnService.getUserTransaction(readOnly, forceWritable); + txn = txnService.getNonPropagatingUserTransaction(readOnly, forceWritable); + txn.begin(); // Wrap it to protect it UserTransactionProtectionAdvise advise = new UserTransactionProtectionAdvise(); @@ -588,7 +586,7 @@ public class RetryingTransactionHelper } finally { - if (startingNew && maxExecutionMs > 0) + if (requiresNew && maxExecutionMs > 0) { synchronized (this) { diff --git a/source/test-java/org/alfresco/repo/transaction/AlfrescoTransactionSupportTest.java b/source/test-java/org/alfresco/repo/transaction/AlfrescoTransactionSupportTest.java index 90b7b90439..81c5165ba0 100644 --- a/source/test-java/org/alfresco/repo/transaction/AlfrescoTransactionSupportTest.java +++ b/source/test-java/org/alfresco/repo/transaction/AlfrescoTransactionSupportTest.java @@ -246,6 +246,12 @@ public class AlfrescoTransactionSupportTest extends TestCase { postCommitReadState[0] = AlfrescoTransactionSupport.getTransactionReadState(); } + + @Override + public void afterRollback() + { + postCommitReadState[0] = AlfrescoTransactionSupport.getTransactionReadState(); + } }; RetryingTransactionCallback getReadStateWork = new RetryingTransactionCallback() @@ -271,6 +277,20 @@ public class AlfrescoTransactionSupportTest extends TestCase checkTxnReadState = transactionService.getRetryingTransactionHelper().doInTransaction(getReadStateWork, false); assertEquals("Expected 'read-write transaction'", TxnReadState.TXN_READ_WRITE, checkTxnReadState); 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 diff --git a/source/test-java/org/alfresco/repo/transaction/RetryingTransactionHelperTest.java b/source/test-java/org/alfresco/repo/transaction/RetryingTransactionHelperTest.java index 0ba4f96219..87d841f607 100644 --- a/source/test-java/org/alfresco/repo/transaction/RetryingTransactionHelperTest.java +++ b/source/test-java/org/alfresco/repo/transaction/RetryingTransactionHelperTest.java @@ -334,7 +334,7 @@ public class RetryingTransactionHelperTest extends TestCase /** * Checks nesting of two transactions with requiresNew == false */ - public void testNestedWithPropogation() + public void testNestedWithPropagation() { RetryingTransactionCallback callback = new RetryingTransactionCallback() { @@ -362,7 +362,7 @@ public class RetryingTransactionHelperTest extends TestCase /** * Checks nesting of two transactions with requiresNew == true */ - public void testNestedWithoutPropogation() + public void testNestedWithoutPropagation() { RetryingTransactionCallback callback = new RetryingTransactionCallback() { @@ -390,17 +390,18 @@ public class RetryingTransactionHelperTest extends TestCase /** * Checks nesting of two transactions with requiresNew == true, * but where the two transactions get involved in a concurrency struggle. - * + *

* Note: skip test for non-MySQL */ - public void testNestedWithoutPropogationConcurrentUntilFailureMySQL() throws InterruptedException + public void testNestedWithoutPropagationConcurrentUntilFailureMySQL() throws InterruptedException { final RetryingTransactionHelper txnHelperForTest = transactionService.getRetryingTransactionHelper(); txnHelperForTest.setMaxRetries(1); 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 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()); } + @SuppressWarnings({ "unchecked", "rawtypes" }) public void testTimeLimit() { final RetryingTransactionHelper txnHelper = new RetryingTransactionHelper(); @@ -617,7 +619,39 @@ public class RetryingTransactionHelperTest extends TestCase 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() + { + @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 caughtExceptions, Pair... startDurationPairs) {