diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index bb03702f7a..bb062a3df6 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -158,6 +158,48 @@ + + + PROPAGATION_REQUIRED + + + false + + + + + + PROPAGATION_REQUIRED + + + true + + + + + + + + + + + + 10 + + + + + + + + + + + + 10 + + + diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml index 25b2581599..d9a3e9e2d6 100644 --- a/config/alfresco/public-services-context.xml +++ b/config/alfresco/public-services-context.xml @@ -1023,6 +1023,106 @@ + + + + + + + getFileInputStream + getContentReader + getDirectoryListing + getDirectoryListingDirect + getDirectoryListingArray + getDeleted + getNextVersionID + getLatestSnapshotID + getAVMStoreVersions + getAVMStores + getAVMStoreRoot + lookup + getPaths + getHeadPaths + getPathsInStoreHead + getIndirectionPath + getHistory + getCommonAncestor + getLayereingInfo + getNodeProperty + getNodeProperties + getStoreProperty + getStoreProperties + queryStorePropertyKey + queryStoresPropertyKeys + getContentDataForRead + getAspects + hasAspect + + + + + + + + + + + getFileOutputStream + createContentWriter + createFile + createDirectory + createLayeredFile + createLayeredDirectory + retargetLayeredDirectory + createAVMStore + createBranch + removeNode + rename + uncover + flatten + createSnapshot + purgeAVMStore + purgeVersion + makePrimary + setOpacity + setNodeProperty + setNodeProperties + deleteNodeProperty + deleteNodeProperties + setStoreProperty + setStoreProperties + deleteStoreProperty + getContentDataForWrite + setContentData + setMetaDataFrom + addAspect + removeAspect + link + forceCopy + copy + renameStore + + + + + + + + org.alfresco.service.cmr.avm.AVMService + + + + avmService + + + + avmServiceWriteTxnAdvisor + avmServiceReadTxnAdvisor + + + + + diff --git a/source/java/org/alfresco/repo/transaction/RetryingTransactionAdvice.java b/source/java/org/alfresco/repo/transaction/RetryingTransactionAdvice.java new file mode 100644 index 0000000000..2032648874 --- /dev/null +++ b/source/java/org/alfresco/repo/transaction/RetryingTransactionAdvice.java @@ -0,0 +1,143 @@ +/** + * + */ +package org.alfresco.repo.transaction; + +import java.util.Random; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.log4j.Logger; +import org.hibernate.StaleObjectStateException; +import org.hibernate.exception.LockAcquisitionException; +import org.springframework.aop.framework.ReflectiveMethodInvocation; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.DeadlockLoserDataAccessException; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; + +/** + * + * @author britt + */ +public class RetryingTransactionAdvice implements MethodInterceptor +{ + private static Logger fgLogger = Logger.getLogger(RetryingTransactionAdvice.class); + + /** + * The transaction manager instance. + */ + private PlatformTransactionManager fTxnManager; + + /** + * The TransactionDefinition. + */ + private TransactionDefinition fDefinition; + + /** + * The maximum number of retries. + */ + private int fMaxRetries; + + /** + * A Random number generator for getting retry intervals. + */ + private Random fRandom; + + public RetryingTransactionAdvice() + { + fRandom = new Random(System.currentTimeMillis()); + } + + /** + * Setter. + */ + public void setTransactionManager(PlatformTransactionManager manager) + { + fTxnManager = manager; + } + + /** + * Setter. + */ + public void setTransactionDefinition(TransactionDefinition def) + { + fDefinition = def; + } + + /** + * Setter. + */ + public void setMaxRetries(int maxRetries) + { + fMaxRetries = maxRetries; + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + public Object invoke(MethodInvocation methodInvocation) throws Throwable + { + RuntimeException lastException = null; + for (int count = 0; fMaxRetries < -1 || count < fMaxRetries; count++) + { + TransactionStatus txn = null; + boolean isNewTxn = false; + try + { + txn = fTxnManager.getTransaction(fDefinition); + isNewTxn = txn.isNewTransaction(); + MethodInvocation clone = ((ReflectiveMethodInvocation)methodInvocation).invocableClone(); + Object result = clone.proceed(); + if (isNewTxn) + { + fTxnManager.commit(txn); + } + if (fgLogger.isDebugEnabled()) + { + if (count != 0) + { + fgLogger.debug("Transaction succeeded after " + count + " retries."); + } + } + return result; + } + catch (Throwable e) + { + if (txn != null && isNewTxn && !txn.isCompleted()) + { + fTxnManager.rollback(txn); + } + if (e instanceof ConcurrencyFailureException || + e instanceof DeadlockLoserDataAccessException || + e instanceof StaleObjectStateException || + e instanceof LockAcquisitionException) + { + if (!isNewTxn) + { + throw (RuntimeException)e; + } + lastException = (RuntimeException)e; + try + { + Thread.sleep(fRandom.nextInt(500 * count + 500)); + } + catch (InterruptedException ie) + { + // Do nothing. + } + continue; + } + if (e instanceof RuntimeException) + { + throw (RuntimeException)e; + } + throw new AlfrescoRuntimeException("Failure in Transaction.", e); + } + } + fgLogger.error("Txn Failed after " + fMaxRetries + " retries:", lastException); + throw lastException; + } +}