Removed RetryingTransactionHelper and friends. AVMService's transactional

behavior is now declaratively specified.  


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3662 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Britt Park
2006-09-03 06:30:05 +00:00
parent 7c70be1811
commit 0b58cca272
10 changed files with 181 additions and 1000 deletions

View File

@@ -7,22 +7,22 @@
<!-- ID Issuers. --> <!-- ID Issuers. -->
<bean id="nodeIssuer" class="org.alfresco.repo.avm.Issuer" <bean id="nodeIssuer" class="org.alfresco.repo.avm.Issuer"
depends-on="retryingTransaction,avmContext" init-method="init"> depends-on="avmContext" init-method="init">
<property name="name"> <property name="name">
<value>node</value> <value>node</value>
</property> </property>
<property name="retryingTransaction"> <property name="transactionService">
<ref bean="retryingTransaction"/> <ref bean="transactionComponent"/>
</property> </property>
</bean> </bean>
<bean id="layerIssuer" class="org.alfresco.repo.avm.Issuer" <bean id="layerIssuer" class="org.alfresco.repo.avm.Issuer"
depends-on="retryingTransaction,avmContext" init-method="init"> depends-on="avmContext" init-method="init">
<property name="name"> <property name="name">
<value>layer</value> <value>layer</value>
</property> </property>
<property name="retryingTransaction"> <property name="transactionService">
<ref bean="retryingTransaction"/> <ref bean="transactionComponent"/>
</property> </property>
</bean> </bean>
@@ -141,45 +141,6 @@
</property> </property>
</bean> </bean>
<!-- A read only DefaultTransactionDefinition -->
<bean id="readTransactionDefinition"
class="org.springframework.transaction.support.DefaultTransactionDefinition">
<property name="propagationBehaviorName">
<value>PROPAGATION_REQUIRED</value>
</property>
<property name="readOnly">
<value>true</value>
</property>
</bean>
<!-- A write DefaultTransactionDefinition -->
<bean id="writeTransactionDefinition"
class="org.springframework.transaction.support.DefaultTransactionDefinition">
<property name="propagationBehaviorName">
<value>PROPAGATION_REQUIRED</value>
</property>
<property name="readOnly">
<value>false</value>
</property>
</bean>
<!-- The Retrying Transaction Helper. -->
<bean id="retryingTransaction"
class="org.alfresco.repo.avm.hibernate.HibernateRetryingTransactionHelper">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="readTransactionDefinition">
<ref bean="readTransactionDefinition"/>
</property>
<property name="writeTransactionDefinition">
<ref bean="writeTransactionDefinition"/>
</property>
</bean>
<bean id="orphanReaper" class="org.alfresco.repo.avm.OrphanReaper" <bean id="orphanReaper" class="org.alfresco.repo.avm.OrphanReaper"
init-method="init" destroy-method="shutDown" depends-on="AVMService"> init-method="init" destroy-method="shutDown" depends-on="AVMService">
<property name="inactiveBaseSleep"> <property name="inactiveBaseSleep">
@@ -194,8 +155,8 @@
<property name="maxQueueLength"> <property name="maxQueueLength">
<value>1000</value> <value>1000</value>
</property> </property>
<property name="retryingTransaction"> <property name="transactionService">
<ref bean="retryingTransaction"/> <ref bean="transactionComponent"/>
</property> </property>
</bean> </bean>

View File

@@ -1007,9 +1007,6 @@
<!-- The AVMService --> <!-- The AVMService -->
<bean id="avmService" class="org.alfresco.repo.avm.AVMServiceImpl"> <bean id="avmService" class="org.alfresco.repo.avm.AVMServiceImpl">
<property name="retryingTransaction">
<ref bean="retryingTransaction"/>
</property>
<property name="avmRepository"> <property name="avmRepository">
<ref bean="avmRepository"/> <ref bean="avmRepository"/>
</property> </property>
@@ -1024,6 +1021,7 @@
</property> </property>
<property name="interceptorNames"> <property name="interceptorNames">
<list> <list>
<idref local="AVMService_transaction"/>
<idref local="AVMService_descriptor"/> <idref local="AVMService_descriptor"/>
</list> </list>
</property> </property>
@@ -1038,6 +1036,22 @@
</property> </property>
</bean> </bean>
<bean id="AVMService_transaction" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="hasAspect">${server.transaction.mode.readOnly}</prop>
<prop key="getContentDataForWrite">${server.transaction.mode.default}</prop>
<prop key="getFileOutputStream">${server.transaction.mode.default}</prop>
<prop key="get*">${server.transaction.mode.readOnly}</prop>
<prop key="lookup">${server.transaction.mode.readOnly}</prop>
<prop key="*">${server.transaction.mode.default}</prop>
</props>
</property>
</bean>
<!-- Workflow Service --> <!-- Workflow Service -->
<bean id="WorkflowService" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="WorkflowService" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -31,6 +31,8 @@ import org.alfresco.service.cmr.avm.AVMException;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.hibernate.HibernateException;
import org.springframework.dao.ConcurrencyFailureException;
/** /**
@@ -222,6 +224,7 @@ class AVMCrawler implements Runnable
} }
catch (Exception e) catch (Exception e)
{ {
e.printStackTrace(System.err);
if (e instanceof AVMException) if (e instanceof AVMException)
{ {
return; return;
@@ -230,7 +233,14 @@ class AVMCrawler implements Runnable
{ {
return; return;
} }
e.printStackTrace(System.err); if (e instanceof ConcurrencyFailureException)
{
return;
}
if (e instanceof HibernateException)
{
return;
}
throw new AVMException("Failure", e); throw new AVMException("Failure", e);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,9 @@
package org.alfresco.repo.avm; package org.alfresco.repo.avm;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.service.transaction.TransactionService;
/** /**
* This is a helper class that knows how to issue identifiers. * This is a helper class that knows how to issue identifiers.
* @author britt * @author britt
@@ -34,9 +37,9 @@ public class Issuer
private String fName; private String fName;
/** /**
* The transactional wrapper. * The transaction service.
*/ */
private RetryingTransactionHelper fTransaction; private TransactionService fTransactionService;
/** /**
* Default constructor. * Default constructor.
@@ -54,13 +57,9 @@ public class Issuer
fName = name; fName = name;
} }
/** public void setTransactionService(TransactionService transactionService)
* Set the transactional wrapper.
* @param retryingTransaction The transactional wrapper.
*/
public void setRetryingTransaction(RetryingTransactionHelper retryingTransaction)
{ {
fTransaction = retryingTransaction; fTransactionService = transactionService;
} }
/** /**
@@ -68,24 +67,23 @@ public class Issuer
*/ */
public void init() public void init()
{ {
class TxnCallback implements RetryingTransactionCallback class TxnWork implements TransactionUtil.TransactionWork<Long>
{ {
public Long value; public Long doWork() throws Exception
public void perform()
{ {
value = AVMContext.fgInstance.fIssuerDAO.getIssuerValue(fName); return AVMContext.fgInstance.fIssuerDAO.getIssuerValue(fName);
} }
}; }
TxnCallback doit = new TxnCallback(); Long result = TransactionUtil.executeInUserTransaction(fTransactionService,
fTransaction.perform(doit, false); new TxnWork(),
if (doit.value == null) true);
if (result == null)
{ {
fNext = 0L; fNext = 0L;
} }
else else
{ {
fNext = doit.value + 1; fNext = result + 1L;
} }
} }

View File

@@ -20,6 +20,8 @@ package org.alfresco.repo.avm;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -31,10 +33,11 @@ import org.apache.commons.logging.LogFactory;
public class OrphanReaper implements Runnable public class OrphanReaper implements Runnable
{ {
private Log fgLogger = LogFactory.getLog(OrphanReaper.class); private Log fgLogger = LogFactory.getLog(OrphanReaper.class);
/** /**
* The HibernateTxn instance. * The Transaction Service
*/ */
private RetryingTransactionHelper fTransaction; private TransactionService fTransactionService;
/** /**
* Inactive base sleep interval. * Inactive base sleep interval.
@@ -119,13 +122,9 @@ public class OrphanReaper implements Runnable
fBatchSize = size; fBatchSize = size;
} }
/** public void setTransactionService(TransactionService transactionService)
* Set the Hibernate Transaction Wrapper.
* @param transaction
*/
public void setRetryingTransaction(RetryingTransactionHelper transaction)
{ {
fTransaction = transaction; fTransactionService = transactionService;
} }
/** /**
@@ -213,9 +212,10 @@ public class OrphanReaper implements Runnable
*/ */
public void doBatch() public void doBatch()
{ {
class TxnCallback implements RetryingTransactionCallback class TxnWork implements TransactionUtil.TransactionWork<Object>
{ {
public void perform() public Object doWork()
throws Exception
{ {
if (fPurgeQueue == null) if (fPurgeQueue == null)
{ {
@@ -223,7 +223,7 @@ public class OrphanReaper implements Runnable
if (nodes.size() == 0) if (nodes.size() == 0)
{ {
fActive = false; fActive = false;
return; return null;
} }
fPurgeQueue = new LinkedList<Long>(); fPurgeQueue = new LinkedList<Long>();
for (AVMNode node : nodes) for (AVMNode node : nodes)
@@ -237,7 +237,7 @@ public class OrphanReaper implements Runnable
if (fPurgeQueue.size() == 0) if (fPurgeQueue.size() == 0)
{ {
fPurgeQueue = null; fPurgeQueue = null;
return; return null;
} }
AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(fPurgeQueue.removeFirst()); AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(fPurgeQueue.removeFirst());
// Save away the ancestor and merged from fields from this node. // Save away the ancestor and merged from fields from this node.
@@ -303,12 +303,13 @@ public class OrphanReaper implements Runnable
AVMContext.fgInstance.fAVMNodeDAO.delete(node); AVMContext.fgInstance.fAVMNodeDAO.delete(node);
} }
} }
return null;
} }
} }
try try
{ {
TxnCallback doit = new TxnCallback(); TransactionUtil.executeInUserTransaction(fTransactionService,
fTransaction.perform(doit, true); new TxnWork());
} }
catch (Exception e) catch (Exception e)
{ {

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.avm;
/**
* Worker object for AVM Retrying Transactions.
* @author britt
*/
public interface RetryingTransactionCallback
{
/**
* Do our work.
*/
public void perform();
}

View File

@@ -1,18 +0,0 @@
package org.alfresco.repo.avm;
/**
* Interface for a retrying transaction. All operations, so far,
* in the AVM repository are idempotent and can thus be retried
* when a transaction fails for synchronization reasons.
* @author britt
*/
public interface RetryingTransactionHelper
{
/**
* Perform a set of operations under a single transaction.
* Keep trying if the operation fails because of a concurrency issue.
* @param callback The worker.
* @param write Whether this is a write operation.
*/
public void perform(RetryingTransactionCallback callback, boolean write);
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.avm.hibernate;
import java.sql.SQLException;
import org.alfresco.repo.avm.RetryingTransactionCallback;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
/**
* This is a wrapper around HibernateTxnCallback implementation.
* @author britt
*/
class HibernateCallbackWrapper implements HibernateCallback
{
/**
* The HibernateTxnCallback to execute.
*/
private RetryingTransactionCallback fCallback;
/**
* Make one up.
* @param callback
*/
public HibernateCallbackWrapper(RetryingTransactionCallback callback)
{
fCallback = callback;
}
/**
* Call the HibernateTxnCallback internally.
* @param session The Hibernate Session.
*/
public Object doInHibernate(Session session) throws HibernateException,
SQLException
{
fCallback.perform();
return null;
}
}

View File

@@ -1,179 +0,0 @@
package org.alfresco.repo.avm.hibernate;
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
import java.util.Random;
import org.alfresco.repo.avm.RetryingTransactionCallback;
import org.alfresco.repo.avm.RetryingTransactionHelper;
import org.alfresco.service.cmr.avm.AVMException;
import org.alfresco.service.cmr.avm.AVMNotFoundException;
import org.apache.log4j.Logger;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.DeadlockLoserDataAccessException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
/**
* Helper for DAOs.
* @author britt
*/
public class HibernateRetryingTransactionHelper extends HibernateTemplate implements RetryingTransactionHelper
{
private static Logger fgLogger = Logger.getLogger(HibernateRetryingTransactionHelper.class);
/**
* The transaction manager.
*/
private PlatformTransactionManager fTransactionManager;
/**
* The read transaction definition.
*/
private TransactionDefinition fReadDefinition;
/**
* The write transaction definition.
*/
private TransactionDefinition fWriteDefinition;
/**
* The random number generator for inter-retry sleep.
*/
private Random fRandom;
/**
* Make one up.
* @param sessionFactory The SessionFactory.
*/
public HibernateRetryingTransactionHelper()
{
fRandom = new Random();
}
/**
* Run an idempotent transaction, repeating invocations as necessary
* for failures caused by deadlocks and lost races.
* @param callback The callback containging the work to do.
* @param write Whether this is a write transaction.
*/
public void perform(RetryingTransactionCallback callback, boolean write)
{
while (true)
{
TransactionStatus status = null;
boolean newTxn = true;
try
{
status =
fTransactionManager.getTransaction(write ? fWriteDefinition : fReadDefinition);
newTxn = status.isNewTransaction();
execute(new HibernateCallbackWrapper(callback));
if (newTxn)
{
fTransactionManager.commit(status);
}
return;
}
catch (Throwable t)
{
if (status == null)
{
t.printStackTrace(System.err);
throw new AVMException("Unrecoverable error.", t);
}
if (newTxn && !status.isCompleted())
{
fTransactionManager.rollback(status);
}
if (!newTxn)
{
if (t instanceof RuntimeException)
{
throw (RuntimeException)t;
}
throw new AVMException("Unrecoverable error.", t);
}
// If we've lost a race or we've deadlocked, retry.
if (t instanceof DeadlockLoserDataAccessException)
{
fgLogger.info("Deadlock");
try
{
long interval;
synchronized (fRandom)
{
interval = fRandom.nextInt(1000);
}
Thread.sleep(interval);
}
catch (InterruptedException ie)
{
// Do nothing.
}
continue;
}
if (t instanceof OptimisticLockingFailureException)
{
fgLogger.info("Lost Race");
continue;
}
if (t instanceof AVMException)
{
throw (AVMException)t;
}
if (t instanceof DataRetrievalFailureException)
{
System.err.println("Data Retrieval Error.");
throw new AVMNotFoundException("Object not found.", t);
}
throw new AVMException("Unrecoverable error.", t);
}
}
}
/**
* Set the transaction manager we are operating under.
* @param manager
*/
public void setTransactionManager(PlatformTransactionManager manager)
{
fTransactionManager = manager;
}
/**
* Set the read Transaction Definition.
* @param def
*/
public void setReadTransactionDefinition(TransactionDefinition def)
{
fReadDefinition = def;
}
/**
* Set the write Transaction Definition.
* @param def
*/
public void setWriteTransactionDefinition(TransactionDefinition def)
{
fWriteDefinition = def;
}
}