mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Added 'version' column to ADM entities
- A patch will assign initial version values to the entities - Deprecated TransactionUtil in favour of the RetryingTransactionHelper - Renamed RetryingTransactionHelper.Callback to RetryingTransactionHelper.RetryingTransactionCallback The name Callback clashes with many other classes in the classpath - Moved loads of components to be included in the retry behaviour Duplicate name checks - This is done using a query, but the entity update is not written to the database early - Concurrent adds of the same-named child node will only fail at the end of the transaction - TODO: Detect the duplicate violation during transaction retrying Workaround for ADMLuceneTest - Disable session size resource management during tests git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5823 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -54,6 +54,7 @@
|
|||||||
<ref bean="patch.db-V2.0-ExplicitIndexes" />
|
<ref bean="patch.db-V2.0-ExplicitIndexes" />
|
||||||
<ref bean="patch.db-V2.0-AVMFKIndexes" />
|
<ref bean="patch.db-V2.0-AVMFKIndexes" />
|
||||||
<ref bean="patch.db-V2.1-JBPMData" />
|
<ref bean="patch.db-V2.1-JBPMData" />
|
||||||
|
<ref bean="patch.db-V2.1-VersionColumns" />
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
--
|
||||||
|
-- Title: Fill 'version' columns with data
|
||||||
|
-- Database: Generic
|
||||||
|
-- Since: V2.1 Schema 54
|
||||||
|
-- Author: Derek Hulley
|
||||||
|
--
|
||||||
|
-- Please contact support@alfresco.com if you need assistance with the upgrade.
|
||||||
|
--
|
||||||
|
|
||||||
|
UPDATE alf_store SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_node SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_child_assoc SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_node_assoc SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_node_status SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_transaction SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_server SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_access_control_list SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_access_control_entry SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_permission SET version = 1 WHERE version IS NULL;
|
||||||
|
UPDATE alf_authority SET version = 1 WHERE version IS NULL;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Record script finish
|
||||||
|
--
|
||||||
|
DELETE FROM alf_applied_patch WHERE id = 'patch.db-V2.1-VersionColumns';
|
||||||
|
INSERT INTO alf_applied_patch
|
||||||
|
(id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
'patch.db-V2.1-VersionColumns', 'Manually executed script upgrade V2.1: Created initial version number for ADM entities',
|
||||||
|
0, 53, -1, 54, null, 'UNKOWN', 1, 1, 'Script completed'
|
||||||
|
);
|
@@ -177,7 +177,7 @@
|
|||||||
<ref bean="sessionFactory" />
|
<ref bean="sessionFactory" />
|
||||||
</property>
|
</property>
|
||||||
<property name="threshold">
|
<property name="threshold">
|
||||||
<value>2000</value>
|
<value>5000</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
@@ -753,4 +753,16 @@
|
|||||||
<ref bean="avmNodeDAO"/>
|
<ref bean="avmNodeDAO"/>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="patch.db-V2.1-VersionColumns" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
|
||||||
|
<property name="id"><value>patch.db-V2.1-VersionColumns</value></property>
|
||||||
|
<property name="description"><value>patch.schemaUpgradeScript.description</value></property>
|
||||||
|
<property name="fixesFromSchema"><value>0</value></property>
|
||||||
|
<property name="fixesToSchema"><value>53</value></property>
|
||||||
|
<property name="targetSchema"><value>54</value></property>
|
||||||
|
<property name="scriptUrl">
|
||||||
|
<value>classpath:alfresco/dbscripts/upgrade/2.1/${db.script.dialect}/AlfrescoSchemaUpdate-2.1-VersionColumns.sql</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -19,4 +19,4 @@ version.build=@build-number@
|
|||||||
|
|
||||||
# Schema number
|
# Schema number
|
||||||
|
|
||||||
version.schema=53
|
version.schema=54
|
||||||
|
@@ -5247,7 +5247,7 @@ public class AVMServiceTest extends AVMServiceTestBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
setupBasicTree();
|
setupBasicTree();
|
||||||
class TxnCallback implements RetryingTransactionHelper.Callback
|
class TxnCallback implements RetryingTransactionHelper.RetryingTransactionCallback
|
||||||
{
|
{
|
||||||
public Object execute()
|
public Object execute()
|
||||||
{
|
{
|
||||||
|
@@ -34,7 +34,7 @@ import org.alfresco.repo.attributes.ListAttributeValue;
|
|||||||
import org.alfresco.repo.attributes.MapAttributeValue;
|
import org.alfresco.repo.attributes.MapAttributeValue;
|
||||||
import org.alfresco.repo.attributes.StringAttributeValue;
|
import org.alfresco.repo.attributes.StringAttributeValue;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.Callback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.cmr.attributes.AttrQueryEquals;
|
import org.alfresco.service.cmr.attributes.AttrQueryEquals;
|
||||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||||
import org.alfresco.service.cmr.avm.AVMExistsException;
|
import org.alfresco.service.cmr.avm.AVMExistsException;
|
||||||
@@ -88,7 +88,7 @@ public class AVMLockingServiceImpl implements AVMLockingService
|
|||||||
|
|
||||||
public void init()
|
public void init()
|
||||||
{
|
{
|
||||||
Callback callback = new Callback()
|
RetryingTransactionCallback callback = new RetryingTransactionCallback()
|
||||||
{
|
{
|
||||||
public Object execute()
|
public Object execute()
|
||||||
{
|
{
|
||||||
|
@@ -38,6 +38,7 @@ import java.util.Locale;
|
|||||||
import org.alfresco.error.StackTraceUtil;
|
import org.alfresco.error.StackTraceUtil;
|
||||||
import org.alfresco.i18n.I18NUtil;
|
import org.alfresco.i18n.I18NUtil;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.cmr.repository.ContentAccessor;
|
import org.alfresco.service.cmr.repository.ContentAccessor;
|
||||||
import org.alfresco.service.cmr.repository.ContentData;
|
import org.alfresco.service.cmr.repository.ContentData;
|
||||||
import org.alfresco.service.cmr.repository.ContentIOException;
|
import org.alfresco.service.cmr.repository.ContentIOException;
|
||||||
@@ -251,8 +252,7 @@ public abstract class AbstractContentAccessor implements ContentAccessor
|
|||||||
// nothing to do
|
// nothing to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RetryingTransactionHelper.Callback cb =
|
RetryingTransactionCallback<Object> cb = new RetryingTransactionCallback<Object>()
|
||||||
new RetryingTransactionHelper.Callback()
|
|
||||||
{
|
{
|
||||||
public Object execute()
|
public Object execute()
|
||||||
{
|
{
|
||||||
@@ -274,7 +274,7 @@ public abstract class AbstractContentAccessor implements ContentAccessor
|
|||||||
{
|
{
|
||||||
cb.execute();
|
cb.execute();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
throw new ContentIOException("Failed to executed channel close callbacks", e);
|
throw new ContentIOException("Failed to executed channel close callbacks", e);
|
||||||
}
|
}
|
||||||
@@ -347,8 +347,7 @@ public abstract class AbstractContentAccessor implements ContentAccessor
|
|||||||
}
|
}
|
||||||
// We're now doing this in a retrying transaction, which means
|
// We're now doing this in a retrying transaction, which means
|
||||||
// that the body of execute() must be idempotent.
|
// that the body of execute() must be idempotent.
|
||||||
RetryingTransactionHelper.Callback cb =
|
RetryingTransactionCallback<Object> cb = new RetryingTransactionCallback<Object>()
|
||||||
new RetryingTransactionHelper.Callback()
|
|
||||||
{
|
{
|
||||||
public Object execute()
|
public Object execute()
|
||||||
{
|
{
|
||||||
@@ -372,7 +371,7 @@ public abstract class AbstractContentAccessor implements ContentAccessor
|
|||||||
{
|
{
|
||||||
cb.execute();
|
cb.execute();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
throw new ContentIOException("Failed to executed channel close callbacks", e);
|
throw new ContentIOException("Failed to executed channel close callbacks", e);
|
||||||
}
|
}
|
||||||
|
@@ -59,6 +59,11 @@ public interface ChildAssoc extends Comparable<ChildAssoc>
|
|||||||
|
|
||||||
public Long getId();
|
public Long getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Return the current version number
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
public Node getParent();
|
public Node getParent();
|
||||||
|
|
||||||
public Node getChild();
|
public Node getChild();
|
||||||
|
@@ -37,7 +37,12 @@ public interface DbAccessControlEntry
|
|||||||
/**
|
/**
|
||||||
* @return Returns the identifier for this object
|
* @return Returns the identifier for this object
|
||||||
*/
|
*/
|
||||||
public long getId();
|
public Long getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the version number for optimistic locking
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the containing access control list
|
* @return Returns the containing access control list
|
||||||
|
@@ -36,7 +36,12 @@ import org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl;
|
|||||||
*/
|
*/
|
||||||
public interface DbAccessControlList
|
public interface DbAccessControlList
|
||||||
{
|
{
|
||||||
public long getId();
|
public Long getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the version number for optimistic locking
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@@ -33,6 +33,11 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public interface DbAuthority extends Serializable
|
public interface DbAuthority extends Serializable
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @return Returns the version number for optimistic locking
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the recipient
|
* @return Returns the recipient
|
||||||
*/
|
*/
|
||||||
|
@@ -38,7 +38,12 @@ public interface DbPermission extends Serializable
|
|||||||
/**
|
/**
|
||||||
* @return Returns the automatically assigned ID
|
* @return Returns the automatically assigned ID
|
||||||
*/
|
*/
|
||||||
public long getId();
|
public Long getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the version number for optimistic locking
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the qualified name of this permission
|
* @return Returns the qualified name of this permission
|
||||||
|
@@ -52,6 +52,11 @@ public interface Node
|
|||||||
*/
|
*/
|
||||||
public Long getId();
|
public Long getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the current version number
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
public Store getStore();
|
public Store getStore();
|
||||||
|
|
||||||
public void setStore(Store store);
|
public void setStore(Store store);
|
||||||
|
@@ -35,8 +35,6 @@ import org.alfresco.service.namespace.QName;
|
|||||||
*/
|
*/
|
||||||
public interface NodeAssoc
|
public interface NodeAssoc
|
||||||
{
|
{
|
||||||
public long getId();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wires up the necessary bits on the source and target nodes so that the association
|
* Wires up the necessary bits on the source and target nodes so that the association
|
||||||
* is immediately bidirectional.
|
* is immediately bidirectional.
|
||||||
@@ -52,6 +50,13 @@ public interface NodeAssoc
|
|||||||
|
|
||||||
public AssociationRef getNodeAssocRef();
|
public AssociationRef getNodeAssocRef();
|
||||||
|
|
||||||
|
public Long getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the current version number
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
public Node getSource();
|
public Node getSource();
|
||||||
|
|
||||||
public Node getTarget();
|
public Node getTarget();
|
||||||
|
@@ -45,6 +45,11 @@ public interface NodeStatus
|
|||||||
*/
|
*/
|
||||||
public void setKey(NodeKey key);
|
public void setKey(NodeKey key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the current version number
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
public Node getNode();
|
public Node getNode();
|
||||||
|
|
||||||
public void setNode(Node node);
|
public void setNode(Node node);
|
||||||
|
@@ -35,6 +35,8 @@ public interface Server
|
|||||||
{
|
{
|
||||||
public Long getId();
|
public Long getId();
|
||||||
|
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
public String getIpAddress();
|
public String getIpAddress();
|
||||||
|
|
||||||
public void setIpAddress(String ipAddress);
|
public void setIpAddress(String ipAddress);
|
||||||
|
@@ -39,6 +39,11 @@ public interface Store
|
|||||||
*/
|
*/
|
||||||
public StoreKey getKey();
|
public StoreKey getKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the current version number used for optimistic locking
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param key the key uniquely identifying this store
|
* @param key the key uniquely identifying this store
|
||||||
*/
|
*/
|
||||||
|
@@ -33,6 +33,8 @@ public interface Transaction
|
|||||||
{
|
{
|
||||||
public Long getId();
|
public Long getId();
|
||||||
|
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
public String getChangeTxnId();
|
public String getChangeTxnId();
|
||||||
|
|
||||||
public void setChangeTxnId(String changeTxnId);
|
public void setChangeTxnId(String changeTxnId);
|
||||||
|
@@ -33,6 +33,7 @@ import org.alfresco.repo.domain.ChildAssoc;
|
|||||||
import org.alfresco.repo.domain.Node;
|
import org.alfresco.repo.domain.Node;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.util.EqualsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
@@ -42,6 +43,7 @@ public class ChildAssocImpl implements ChildAssoc, Serializable
|
|||||||
private static final long serialVersionUID = -8993272236626580410L;
|
private static final long serialVersionUID = -8993272236626580410L;
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
private Long version;
|
||||||
private Node parent;
|
private Node parent;
|
||||||
private Node child;
|
private Node child;
|
||||||
private QName typeQName;
|
private QName typeQName;
|
||||||
@@ -127,6 +129,32 @@ public class ChildAssocImpl implements ChildAssoc, Serializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (obj == this)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (!(obj instanceof ChildAssoc))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ChildAssoc that = (ChildAssoc) obj;
|
||||||
|
return (EqualsHelper.nullSafeEquals(this.getTypeQName(), that.getTypeQName())
|
||||||
|
&& EqualsHelper.nullSafeEquals(this.getQname(), that.getQname())
|
||||||
|
&& EqualsHelper.nullSafeEquals(this.getChild(), that.getChild())
|
||||||
|
&& EqualsHelper.nullSafeEquals(this.getParent(), that.getParent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return (child == null ? 0 : child.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
StringBuffer sb = new StringBuffer(32);
|
StringBuffer sb = new StringBuffer(32);
|
||||||
@@ -192,6 +220,20 @@ public class ChildAssocImpl implements ChildAssoc, Serializable
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public Node getParent()
|
public Node getParent()
|
||||||
{
|
{
|
||||||
return parent;
|
return parent;
|
||||||
|
@@ -42,18 +42,14 @@ public class DbAccessControlEntryImpl extends LifecycleAdapter
|
|||||||
{
|
{
|
||||||
private static final long serialVersionUID = -418837862334064582L;
|
private static final long serialVersionUID = -418837862334064582L;
|
||||||
|
|
||||||
/** The object id */
|
private Long id;
|
||||||
private long id;
|
private Long version;
|
||||||
|
|
||||||
/** The container of these entries */
|
/** The container of these entries */
|
||||||
private DbAccessControlList accessControlList;
|
private DbAccessControlList accessControlList;
|
||||||
|
|
||||||
/** The permission to which this applies (non null - all is a special string) */
|
/** The permission to which this applies (non null - all is a special string) */
|
||||||
private DbPermission permission;
|
private DbPermission permission;
|
||||||
|
|
||||||
/** The recipient to which this applies (non null - all is a special string) */
|
/** The recipient to which this applies (non null - all is a special string) */
|
||||||
private DbAuthority authority;
|
private DbAuthority authority;
|
||||||
|
|
||||||
/** Is this permission allowed? */
|
/** Is this permission allowed? */
|
||||||
private boolean allowed;
|
private boolean allowed;
|
||||||
|
|
||||||
@@ -113,7 +109,7 @@ public class DbAccessControlEntryImpl extends LifecycleAdapter
|
|||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getId()
|
public Long getId()
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -121,11 +117,26 @@ public class DbAccessControlEntryImpl extends LifecycleAdapter
|
|||||||
/**
|
/**
|
||||||
* For Hibernate use
|
* For Hibernate use
|
||||||
*/
|
*/
|
||||||
/* package */ void setId(long id)
|
@SuppressWarnings("unused")
|
||||||
|
private void setId(Long id)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public DbAccessControlList getAccessControlList()
|
public DbAccessControlList getAccessControlList()
|
||||||
{
|
{
|
||||||
return accessControlList;
|
return accessControlList;
|
||||||
|
@@ -51,7 +51,8 @@ public class DbAccessControlListImpl extends LifecycleAdapter
|
|||||||
|
|
||||||
private static Log logger = LogFactory.getLog(DbAccessControlListImpl.class);
|
private static Log logger = LogFactory.getLog(DbAccessControlListImpl.class);
|
||||||
|
|
||||||
private long id;
|
private Long id;
|
||||||
|
private Long version;
|
||||||
private Set<DbAccessControlEntry> entries;
|
private Set<DbAccessControlEntry> entries;
|
||||||
private boolean inherits;
|
private boolean inherits;
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ public class DbAccessControlListImpl extends LifecycleAdapter
|
|||||||
return (inherits == false ? 0 : 17);
|
return (inherits == false ? 0 : 17);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getId()
|
public Long getId()
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -103,11 +104,25 @@ public class DbAccessControlListImpl extends LifecycleAdapter
|
|||||||
* Hibernate use
|
* Hibernate use
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private void setId(long id)
|
private void setId(Long id)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<DbAccessControlEntry> getEntries()
|
public Set<DbAccessControlEntry> getEntries()
|
||||||
{
|
{
|
||||||
return entries;
|
return entries;
|
||||||
|
@@ -47,6 +47,7 @@ public class DbAuthorityImpl extends LifecycleAdapter
|
|||||||
|
|
||||||
private static Log logger = LogFactory.getLog(DbAuthorityImpl.class);
|
private static Log logger = LogFactory.getLog(DbAuthorityImpl.class);
|
||||||
|
|
||||||
|
private Long version;
|
||||||
private String recipient;
|
private String recipient;
|
||||||
private Set<String> externalKeys;
|
private Set<String> externalKeys;
|
||||||
|
|
||||||
@@ -105,6 +106,20 @@ public class DbAuthorityImpl extends LifecycleAdapter
|
|||||||
return super.onDelete(session);
|
return super.onDelete(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public String getRecipient()
|
public String getRecipient()
|
||||||
{
|
{
|
||||||
return recipient;
|
return recipient;
|
||||||
|
@@ -48,7 +48,8 @@ public class DbPermissionImpl extends LifecycleAdapter
|
|||||||
|
|
||||||
private static Log logger = LogFactory.getLog(DbPermissionImpl.class);
|
private static Log logger = LogFactory.getLog(DbPermissionImpl.class);
|
||||||
|
|
||||||
private long id;
|
private Long id;
|
||||||
|
private Long version;
|
||||||
private QName typeQname;
|
private QName typeQname;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ public class DbPermissionImpl extends LifecycleAdapter
|
|||||||
return super.onDelete(session);
|
return super.onDelete(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getId()
|
public Long getId()
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -129,11 +130,25 @@ public class DbPermissionImpl extends LifecycleAdapter
|
|||||||
* For Hibernate use
|
* For Hibernate use
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private void setId(long id)
|
private void setId(Long id)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public QName getTypeQname()
|
public QName getTypeQname()
|
||||||
{
|
{
|
||||||
return typeQname;
|
return typeQname;
|
||||||
|
@@ -49,6 +49,7 @@ import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
|||||||
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
||||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
import org.alfresco.util.BaseSpringTest;
|
import org.alfresco.util.BaseSpringTest;
|
||||||
@@ -178,6 +179,8 @@ public class HibernateNodeTest extends BaseSpringTest
|
|||||||
// Sybase
|
// Sybase
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
|
// Just clear out any pending changes
|
||||||
|
getSession().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -584,4 +587,58 @@ public class HibernateNodeTest extends BaseSpringTest
|
|||||||
getSession().flush();
|
getSession().flush();
|
||||||
getSession().clear();
|
getSession().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testDeletesAndFlush() throws Exception
|
||||||
|
{
|
||||||
|
// Create parent node
|
||||||
|
Node parentNode = new NodeImpl();
|
||||||
|
parentNode.setStore(store);
|
||||||
|
parentNode.setUuid(GUID.generate());
|
||||||
|
parentNode.setTypeQName(ContentModel.TYPE_CONTAINER);
|
||||||
|
Long nodeIdOne = (Long) getSession().save(parentNode);
|
||||||
|
// Create child node
|
||||||
|
Node childNode = new NodeImpl();
|
||||||
|
childNode.setStore(store);
|
||||||
|
childNode.setUuid(GUID.generate());
|
||||||
|
childNode.setTypeQName(ContentModel.TYPE_CONTENT);
|
||||||
|
Long nodeIdTwo = (Long) getSession().save(childNode);
|
||||||
|
// Get them into the database
|
||||||
|
getSession().flush();
|
||||||
|
|
||||||
|
// Now create a loads of associations
|
||||||
|
int assocCount = 1000;
|
||||||
|
List<Long> assocIds = new ArrayList<Long>(assocCount);
|
||||||
|
for (int i = 0; i < assocCount; i++)
|
||||||
|
{
|
||||||
|
ChildAssoc assoc = new ChildAssocImpl();
|
||||||
|
assoc.buildAssociation(parentNode, childNode);
|
||||||
|
assoc.setIsPrimary(false);
|
||||||
|
assoc.setTypeQName(QName.createQName(null, "TYPE"));
|
||||||
|
assoc.setQname(QName.createQName(null, "" + System.nanoTime()));
|
||||||
|
assoc.setChildNodeName(GUID.generate()); // It must be unique
|
||||||
|
assoc.setChildNodeNameCrc(-1L);
|
||||||
|
Long assocId = (Long) getSession().save(assoc);
|
||||||
|
assocIds.add(assocId);
|
||||||
|
}
|
||||||
|
// Flush and clear the lot
|
||||||
|
getSession().flush();
|
||||||
|
getSession().clear();
|
||||||
|
|
||||||
|
// Now we delete the entities, flushing and clearing every 100 deletes
|
||||||
|
int count = 0;
|
||||||
|
for (Long assocId : assocIds)
|
||||||
|
{
|
||||||
|
// Load the entity
|
||||||
|
ChildAssoc assoc = (ChildAssoc) getSession().get(ChildAssocImpl.class, assocId);
|
||||||
|
assertNotNull("Entity should exist", assoc);
|
||||||
|
getSession().delete(assoc);
|
||||||
|
// Do we flush and clear
|
||||||
|
if (count % 100 == 0)
|
||||||
|
{
|
||||||
|
getSession().flush();
|
||||||
|
getSession().clear();
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -38,6 +38,9 @@
|
|||||||
<!-- the store-unique identifier -->
|
<!-- the store-unique identifier -->
|
||||||
<property name="uuid" column="uuid" type="string" length="36" />
|
<property name="uuid" column="uuid" type="string" length="36" />
|
||||||
</natural-id>
|
</natural-id>
|
||||||
|
<!-- Optimistic locking -->
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
|
|
||||||
<property name="typeQName" column="type_qname" type="QName" length="255" not-null="true" />
|
<property name="typeQName" column="type_qname" type="QName" length="255" not-null="true" />
|
||||||
<!-- forward assoc to access control list (optional) -->
|
<!-- forward assoc to access control list (optional) -->
|
||||||
<many-to-one
|
<many-to-one
|
||||||
@@ -115,6 +118,8 @@
|
|||||||
<key-property name="identifier" length="100" />
|
<key-property name="identifier" length="100" />
|
||||||
<key-property name="guid" length="36" />
|
<key-property name="guid" length="36" />
|
||||||
</composite-id>
|
</composite-id>
|
||||||
|
<!-- Optimistic locking -->
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
<!-- forward assoc to transaction -->
|
<!-- forward assoc to transaction -->
|
||||||
<many-to-one
|
<many-to-one
|
||||||
name="transaction"
|
name="transaction"
|
||||||
@@ -148,13 +153,15 @@
|
|||||||
<id name="id" column="id" type="long" >
|
<id name="id" column="id" type="long" >
|
||||||
<generator class="native" />
|
<generator class="native" />
|
||||||
</id>
|
</id>
|
||||||
|
<!-- Optimistic locking -->
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
<!-- forward assoc to parent node -->
|
<!-- forward assoc to parent node -->
|
||||||
<many-to-one
|
<many-to-one
|
||||||
name="parent"
|
name="parent"
|
||||||
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
||||||
lazy="proxy"
|
lazy="proxy"
|
||||||
fetch="select"
|
fetch="select"
|
||||||
optimistic-lock="true"
|
optimistic-lock="false"
|
||||||
not-null="true"
|
not-null="true"
|
||||||
unique-key="UIDX_CHILD_NAME" >
|
unique-key="UIDX_CHILD_NAME" >
|
||||||
<column name="parent_node_id" not-null="true" />
|
<column name="parent_node_id" not-null="true" />
|
||||||
@@ -165,7 +172,7 @@
|
|||||||
lazy="proxy"
|
lazy="proxy"
|
||||||
fetch="select"
|
fetch="select"
|
||||||
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
||||||
optimistic-lock="true"
|
optimistic-lock="false"
|
||||||
not-null="true" >
|
not-null="true" >
|
||||||
<column name="child_node_id" not-null="true"/>
|
<column name="child_node_id" not-null="true"/>
|
||||||
</many-to-one>
|
</many-to-one>
|
||||||
@@ -190,6 +197,7 @@
|
|||||||
<many-to-one
|
<many-to-one
|
||||||
name="source"
|
name="source"
|
||||||
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
||||||
|
optimistic-lock="false"
|
||||||
lazy="false"
|
lazy="false"
|
||||||
fetch="join"
|
fetch="join"
|
||||||
not-null="true" >
|
not-null="true" >
|
||||||
@@ -199,6 +207,7 @@
|
|||||||
<many-to-one
|
<many-to-one
|
||||||
name="target"
|
name="target"
|
||||||
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
||||||
|
optimistic-lock="false"
|
||||||
lazy="false"
|
lazy="false"
|
||||||
fetch="join"
|
fetch="join"
|
||||||
not-null="true" >
|
not-null="true" >
|
||||||
@@ -206,6 +215,8 @@
|
|||||||
</many-to-one>
|
</many-to-one>
|
||||||
<property name="typeQName" column="type_qname" type="QName" length="255" not-null="true" />
|
<property name="typeQName" column="type_qname" type="QName" length="255" not-null="true" />
|
||||||
</natural-id>
|
</natural-id>
|
||||||
|
<!-- Optimistic locking -->
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
</class>
|
</class>
|
||||||
|
|
||||||
<query name="store.GetAllStores">
|
<query name="store.GetAllStores">
|
||||||
@@ -272,6 +283,17 @@
|
|||||||
assoc.id
|
assoc.id
|
||||||
</query>
|
</query>
|
||||||
|
|
||||||
|
<query name="node.GetChildAssocByShortName">
|
||||||
|
select
|
||||||
|
assoc
|
||||||
|
from
|
||||||
|
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||||
|
where
|
||||||
|
assoc.parent.id = :parentId and
|
||||||
|
assoc.childNodeName = :childNodeName and
|
||||||
|
assoc.childNodeNameCrc = :childNodeNameCrc
|
||||||
|
</query>
|
||||||
|
|
||||||
<query name="node.GetChildAssocByTypeAndName">
|
<query name="node.GetChildAssocByTypeAndName">
|
||||||
select
|
select
|
||||||
assoc
|
assoc
|
||||||
|
@@ -44,7 +44,8 @@ public class NodeAssocImpl implements NodeAssoc, Serializable
|
|||||||
{
|
{
|
||||||
private static final long serialVersionUID = 864534636913524867L;
|
private static final long serialVersionUID = 864534636913524867L;
|
||||||
|
|
||||||
private long id;
|
private Long id;
|
||||||
|
private Long version;
|
||||||
private Node source;
|
private Node source;
|
||||||
private Node target;
|
private Node target;
|
||||||
private QName typeQName;
|
private QName typeQName;
|
||||||
@@ -149,7 +150,7 @@ public class NodeAssocImpl implements NodeAssoc, Serializable
|
|||||||
return (typeQName == null ? 0 : typeQName.hashCode());
|
return (typeQName == null ? 0 : typeQName.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getId()
|
public Long getId()
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -163,6 +164,20 @@ public class NodeAssocImpl implements NodeAssoc, Serializable
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public Node getSource()
|
public Node getSource()
|
||||||
{
|
{
|
||||||
return source;
|
return source;
|
||||||
|
@@ -56,6 +56,7 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable
|
|||||||
private static final long serialVersionUID = -2101330674810283053L;
|
private static final long serialVersionUID = -2101330674810283053L;
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
private Long version;
|
||||||
private Store store;
|
private Store store;
|
||||||
private String uuid;
|
private String uuid;
|
||||||
private QName typeQName;
|
private QName typeQName;
|
||||||
@@ -179,6 +180,20 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public Store getStore()
|
public Store getStore()
|
||||||
{
|
{
|
||||||
return store;
|
return store;
|
||||||
|
@@ -42,6 +42,7 @@ public class NodeStatusImpl implements NodeStatus, Serializable
|
|||||||
private static final long serialVersionUID = -802747893314715639L;
|
private static final long serialVersionUID = -802747893314715639L;
|
||||||
|
|
||||||
private NodeKey key;
|
private NodeKey key;
|
||||||
|
private Long version;
|
||||||
private Node node;
|
private Node node;
|
||||||
private Transaction transaction;
|
private Transaction transaction;
|
||||||
|
|
||||||
@@ -85,6 +86,20 @@ public class NodeStatusImpl implements NodeStatus, Serializable
|
|||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public Node getNode()
|
public Node getNode()
|
||||||
{
|
{
|
||||||
return node;
|
return node;
|
||||||
|
@@ -19,6 +19,8 @@
|
|||||||
<generator class="native" />
|
<generator class="native" />
|
||||||
</id>
|
</id>
|
||||||
|
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
|
|
||||||
<set name="entries"
|
<set name="entries"
|
||||||
inverse="true"
|
inverse="true"
|
||||||
lazy="false"
|
lazy="false"
|
||||||
@@ -74,6 +76,8 @@
|
|||||||
not-null="true" />
|
not-null="true" />
|
||||||
</natural-id>
|
</natural-id>
|
||||||
|
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
|
|
||||||
<property name="allowed" column="allowed" type="boolean" not-null="true" />
|
<property name="allowed" column="allowed" type="boolean" not-null="true" />
|
||||||
|
|
||||||
</class>
|
</class>
|
||||||
@@ -97,6 +101,8 @@
|
|||||||
<property name="name" type="string" length="100" column="name" />
|
<property name="name" type="string" length="100" column="name" />
|
||||||
</natural-id>
|
</natural-id>
|
||||||
|
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
|
|
||||||
</class>
|
</class>
|
||||||
|
|
||||||
<class
|
<class
|
||||||
@@ -111,6 +117,8 @@
|
|||||||
|
|
||||||
<id name="recipient" column="recipient" type="string" length="100" />
|
<id name="recipient" column="recipient" type="string" length="100" />
|
||||||
|
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
|
|
||||||
<set
|
<set
|
||||||
name="externalKeys"
|
name="externalKeys"
|
||||||
table="alf_auth_ext_keys"
|
table="alf_auth_ext_keys"
|
||||||
|
@@ -41,6 +41,7 @@ public class ServerImpl extends LifecycleAdapter implements Server, Serializable
|
|||||||
private static final long serialVersionUID = 8063452519040344479L;
|
private static final long serialVersionUID = 8063452519040344479L;
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
private Long version;
|
||||||
private String ipAddress;
|
private String ipAddress;
|
||||||
|
|
||||||
public ServerImpl()
|
public ServerImpl()
|
||||||
@@ -77,6 +78,20 @@ public class ServerImpl extends LifecycleAdapter implements Server, Serializable
|
|||||||
return ipAddress;
|
return ipAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public void setIpAddress(String ipAddress)
|
public void setIpAddress(String ipAddress)
|
||||||
{
|
{
|
||||||
this.ipAddress = ipAddress;
|
this.ipAddress = ipAddress;
|
||||||
|
@@ -27,6 +27,7 @@ package org.alfresco.repo.domain.hibernate;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||||
import org.alfresco.util.resource.MethodResourceManager;
|
import org.alfresco.util.resource.MethodResourceManager;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
@@ -50,10 +51,49 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
|||||||
*/
|
*/
|
||||||
public class SessionSizeResourceManager extends HibernateDaoSupport implements MethodResourceManager
|
public class SessionSizeResourceManager extends HibernateDaoSupport implements MethodResourceManager
|
||||||
{
|
{
|
||||||
|
/** key to store the local flag to disable resource control during the current transaction */
|
||||||
|
private static final String KEY_DISABLE_IN_TRANSACTION = "SessionSizeResourceManager.DisableInTransaction";
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(SessionSizeResourceManager.class);
|
private static Log logger = LogFactory.getLog(SessionSizeResourceManager.class);
|
||||||
|
|
||||||
/** Default 1000 */
|
/** Default 1000 */
|
||||||
private int threshold = 1000;
|
private int threshold;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable resource management for the duration of the current transaction. This is temporary
|
||||||
|
* and relies on an active transaction.
|
||||||
|
*/
|
||||||
|
public static void setDisableInTransaction()
|
||||||
|
{
|
||||||
|
AlfrescoTransactionSupport.bindResource(KEY_DISABLE_IN_TRANSACTION, Boolean.TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns true if the resource management must be ignored in the current transaction.
|
||||||
|
* If <code>false</code>, the global setting will take effect.
|
||||||
|
*
|
||||||
|
* @see #setDisableInTransaction()
|
||||||
|
*/
|
||||||
|
public static boolean isDisableInTransaction()
|
||||||
|
{
|
||||||
|
Boolean disableInTransaction = (Boolean) AlfrescoTransactionSupport.getResource(KEY_DISABLE_IN_TRANSACTION);
|
||||||
|
if (disableInTransaction == null || disableInTransaction == Boolean.FALSE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default public constructor required for bean instantiation.
|
||||||
|
*/
|
||||||
|
public SessionSizeResourceManager()
|
||||||
|
{
|
||||||
|
this.threshold = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link Session#clear()} threshold. If the number of entities and collections in the
|
* Set the {@link Session#clear()} threshold. If the number of entities and collections in the
|
||||||
@@ -74,6 +114,12 @@ public class SessionSizeResourceManager extends HibernateDaoSupport implements M
|
|||||||
long transactionElapsedTimeNs,
|
long transactionElapsedTimeNs,
|
||||||
Method currentMethod)
|
Method currentMethod)
|
||||||
{
|
{
|
||||||
|
if (isDisableInTransaction())
|
||||||
|
{
|
||||||
|
// Don't do anything
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We are go for interfering
|
||||||
Session session = getSession(false);
|
Session session = getSession(false);
|
||||||
SessionStatistics stats = session.getStatistics();
|
SessionStatistics stats = session.getStatistics();
|
||||||
int entityCount = stats.getEntityCount();
|
int entityCount = stats.getEntityCount();
|
||||||
|
@@ -19,6 +19,8 @@
|
|||||||
<key-property name="protocol" length="50" />
|
<key-property name="protocol" length="50" />
|
||||||
<key-property name="identifier" length="100" />
|
<key-property name="identifier" length="100" />
|
||||||
</composite-id>
|
</composite-id>
|
||||||
|
<!-- Optimistic locking -->
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
<!-- forward assoc to root node -->
|
<!-- forward assoc to root node -->
|
||||||
<many-to-one
|
<many-to-one
|
||||||
name="rootNode"
|
name="rootNode"
|
||||||
|
@@ -44,6 +44,7 @@ public class StoreImpl implements Store, Serializable
|
|||||||
private static final long serialVersionUID = -6135740209100885890L;
|
private static final long serialVersionUID = -6135740209100885890L;
|
||||||
|
|
||||||
private StoreKey key;
|
private StoreKey key;
|
||||||
|
private Long version;
|
||||||
private Node rootNode;
|
private Node rootNode;
|
||||||
|
|
||||||
private transient ReadLock refReadLock;
|
private transient ReadLock refReadLock;
|
||||||
@@ -148,6 +149,20 @@ public class StoreImpl implements Store, Serializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public Node getRootNode()
|
public Node getRootNode()
|
||||||
{
|
{
|
||||||
return rootNode;
|
return rootNode;
|
||||||
|
@@ -19,6 +19,8 @@
|
|||||||
<id name="id" column="id" type="long" >
|
<id name="id" column="id" type="long" >
|
||||||
<generator class="native" />
|
<generator class="native" />
|
||||||
</id>
|
</id>
|
||||||
|
<!-- Optimistic locking -->
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
<!-- forward assoc to server IP -->
|
<!-- forward assoc to server IP -->
|
||||||
<many-to-one
|
<many-to-one
|
||||||
name="server"
|
name="server"
|
||||||
@@ -48,6 +50,8 @@
|
|||||||
<natural-id>
|
<natural-id>
|
||||||
<property name="ipAddress" column="ip_address" type="string" length="15" not-null="true" />
|
<property name="ipAddress" column="ip_address" type="string" length="15" not-null="true" />
|
||||||
</natural-id>
|
</natural-id>
|
||||||
|
<!-- Optimistic locking -->
|
||||||
|
<version column="version" name="version" type="long" />
|
||||||
</class>
|
</class>
|
||||||
|
|
||||||
<query name="server.getServerByIpAddress">
|
<query name="server.getServerByIpAddress">
|
||||||
|
@@ -42,6 +42,7 @@ public class TransactionImpl extends LifecycleAdapter implements Transaction, Se
|
|||||||
private static final long serialVersionUID = -8264339795578077552L;
|
private static final long serialVersionUID = -8264339795578077552L;
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
private Long version;
|
||||||
private String changeTxnId;
|
private String changeTxnId;
|
||||||
private Server server;
|
private Server server;
|
||||||
|
|
||||||
@@ -74,6 +75,20 @@ public class TransactionImpl extends LifecycleAdapter implements Transaction, Se
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Hibernate use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void setVersion(Long version)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
public String getChangeTxnId()
|
public String getChangeTxnId()
|
||||||
{
|
{
|
||||||
return changeTxnId;
|
return changeTxnId;
|
||||||
|
@@ -35,8 +35,8 @@ import org.alfresco.error.AlfrescoRuntimeException;
|
|||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
|
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
import org.alfresco.repo.transaction.TransactionUtil;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.model.FileFolderService;
|
import org.alfresco.service.cmr.model.FileFolderService;
|
||||||
import org.alfresco.service.cmr.model.FileInfo;
|
import org.alfresco.service.cmr.model.FileInfo;
|
||||||
@@ -47,7 +47,6 @@ import org.alfresco.service.cmr.repository.NodeService;
|
|||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.cmr.search.ResultSet;
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
import org.alfresco.service.cmr.search.SearchService;
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
|
||||||
import org.alfresco.util.ApplicationContextHelper;
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
import org.alfresco.util.GUID;
|
import org.alfresco.util.GUID;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
@@ -71,7 +70,7 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
|
|
||||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||||
|
|
||||||
private TransactionService transactionService;
|
private RetryingTransactionHelper retryingTransactionHelper;
|
||||||
private AuthenticationComponent authenticationComponent;
|
private AuthenticationComponent authenticationComponent;
|
||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
private FileFolderService fileFolderService;
|
private FileFolderService fileFolderService;
|
||||||
@@ -82,7 +81,7 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
public void setUp() throws Exception
|
public void setUp() throws Exception
|
||||||
{
|
{
|
||||||
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
||||||
transactionService = serviceRegistry.getTransactionService();
|
retryingTransactionHelper = (RetryingTransactionHelper) ctx.getBean("retryingTransactionHelper");
|
||||||
authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
|
authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
|
||||||
nodeService = serviceRegistry.getNodeService();
|
nodeService = serviceRegistry.getNodeService();
|
||||||
fileFolderService = serviceRegistry.getFileFolderService();
|
fileFolderService = serviceRegistry.getFileFolderService();
|
||||||
@@ -138,9 +137,9 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
final int fileCount,
|
final int fileCount,
|
||||||
final double[] dumpPoints)
|
final double[] dumpPoints)
|
||||||
{
|
{
|
||||||
TransactionWork<NodeRef[]> createFoldersWork = new TransactionWork<NodeRef[]>()
|
RetryingTransactionCallback<NodeRef[]> createFoldersCallback = new RetryingTransactionCallback<NodeRef[]>()
|
||||||
{
|
{
|
||||||
public NodeRef[] doWork() throws Exception
|
public NodeRef[] execute() throws Exception
|
||||||
{
|
{
|
||||||
NodeRef[] folders = new NodeRef[folderCount];
|
NodeRef[] folders = new NodeRef[folderCount];
|
||||||
for (int i = 0; i < folderCount; i++)
|
for (int i = 0; i < folderCount; i++)
|
||||||
@@ -155,9 +154,7 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
return folders;
|
return folders;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
final NodeRef[] folders = TransactionUtil.executeInUserTransaction(
|
final NodeRef[] folders = retryingTransactionHelper.doInTransaction(createFoldersCallback);
|
||||||
transactionService,
|
|
||||||
createFoldersWork);
|
|
||||||
// the worker that will load the files into the folders
|
// the worker that will load the files into the folders
|
||||||
Runnable runnable = new Runnable()
|
Runnable runnable = new Runnable()
|
||||||
{
|
{
|
||||||
@@ -192,9 +189,9 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
for (int j = 0; j < folders.length; j++)
|
for (int j = 0; j < folders.length; j++)
|
||||||
{
|
{
|
||||||
final NodeRef folderRef = folders[j];
|
final NodeRef folderRef = folders[j];
|
||||||
TransactionWork<FileInfo> createFileWork = new TransactionWork<FileInfo>()
|
RetryingTransactionCallback<FileInfo> createFileCallback = new RetryingTransactionCallback<FileInfo>()
|
||||||
{
|
{
|
||||||
public FileInfo doWork() throws Exception
|
public FileInfo execute() throws Exception
|
||||||
{
|
{
|
||||||
FileInfo fileInfo = fileFolderService.create(
|
FileInfo fileInfo = fileFolderService.create(
|
||||||
folderRef,
|
folderRef,
|
||||||
@@ -208,7 +205,7 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
return fileInfo;
|
return fileInfo;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TransactionUtil.executeInUserTransaction(transactionService, createFileWork);
|
retryingTransactionHelper.doInTransaction(createFileCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dumpResults(fileCount);
|
dumpResults(fileCount);
|
||||||
@@ -257,6 +254,7 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private void readStructure(
|
private void readStructure(
|
||||||
final NodeRef parentNodeRef,
|
final NodeRef parentNodeRef,
|
||||||
final int threadCount,
|
final int threadCount,
|
||||||
@@ -277,9 +275,9 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
for (ChildAssociationRef childAssociationRef : children)
|
for (ChildAssociationRef childAssociationRef : children)
|
||||||
{
|
{
|
||||||
final NodeRef folderRef = childAssociationRef.getChildRef();
|
final NodeRef folderRef = childAssociationRef.getChildRef();
|
||||||
TransactionWork<Object> readWork = new TransactionWork<Object>()
|
RetryingTransactionCallback<Object> readCallback = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork() throws Exception
|
public Object execute() throws Exception
|
||||||
{
|
{
|
||||||
// read the child associations of the folder
|
// read the child associations of the folder
|
||||||
nodeService.getChildAssocs(folderRef);
|
nodeService.getChildAssocs(folderRef);
|
||||||
@@ -289,7 +287,7 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
TransactionUtil.executeInUserTransaction(transactionService, readWork, true);
|
retryingTransactionHelper.doInTransaction(readCallback, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,16 +335,16 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
// {
|
// {
|
||||||
// buildStructure(rootFolderRef, 4, true, 10, 100, new double[] {0.25, 0.50, 0.75});
|
// buildStructure(rootFolderRef, 4, true, 10, 100, new double[] {0.25, 0.50, 0.75});
|
||||||
// }
|
// }
|
||||||
public void test_1_ordered_100_100() throws Exception
|
// public void test_1_ordered_100_100() throws Exception
|
||||||
{
|
// {
|
||||||
buildStructure(
|
// buildStructure(
|
||||||
rootFolderRef,
|
// rootFolderRef,
|
||||||
1,
|
// 1,
|
||||||
false,
|
// false,
|
||||||
100,
|
// 100,
|
||||||
100,
|
// 100,
|
||||||
new double[] {0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
|
// new double[] {0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
|
||||||
}
|
// }
|
||||||
// public void test_1_shuffled_10_400() throws Exception
|
// public void test_1_shuffled_10_400() throws Exception
|
||||||
// {
|
// {
|
||||||
// buildStructure(
|
// buildStructure(
|
||||||
@@ -357,16 +355,16 @@ public class FileFolderPerformanceTester extends TestCase
|
|||||||
// 400,
|
// 400,
|
||||||
// new double[] {0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
|
// new double[] {0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
|
||||||
// }
|
// }
|
||||||
// public void test_4_shuffled_10_100() throws Exception
|
public void test_4_shuffled_10_100() throws Exception
|
||||||
// {
|
{
|
||||||
// buildStructure(
|
buildStructure(
|
||||||
// rootFolderRef,
|
rootFolderRef,
|
||||||
// 4,
|
4,
|
||||||
// true,
|
true,
|
||||||
// 10,
|
10,
|
||||||
// 100,
|
100,
|
||||||
// new double[] {0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
|
new double[] {0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
|
||||||
// }
|
}
|
||||||
// public void test_1_ordered_1_50000() throws Exception
|
// public void test_1_ordered_1_50000() throws Exception
|
||||||
// {
|
// {
|
||||||
// buildStructure(
|
// buildStructure(
|
||||||
|
@@ -51,6 +51,7 @@ import org.alfresco.repo.policy.JavaBehaviour;
|
|||||||
import org.alfresco.repo.policy.PolicyComponent;
|
import org.alfresco.repo.policy.PolicyComponent;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||||
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||||
@@ -140,6 +141,7 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
|
|||||||
protected PolicyComponent policyComponent;
|
protected PolicyComponent policyComponent;
|
||||||
protected DictionaryService dictionaryService;
|
protected DictionaryService dictionaryService;
|
||||||
protected TransactionService transactionService;
|
protected TransactionService transactionService;
|
||||||
|
protected RetryingTransactionHelper retryingTransactionHelper;
|
||||||
protected AuthenticationComponent authenticationComponent;
|
protected AuthenticationComponent authenticationComponent;
|
||||||
protected NodeDaoService nodeDaoService;
|
protected NodeDaoService nodeDaoService;
|
||||||
protected NodeService nodeService;
|
protected NodeService nodeService;
|
||||||
@@ -151,6 +153,7 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
|
|||||||
{
|
{
|
||||||
super.onSetUpInTransaction();
|
super.onSetUpInTransaction();
|
||||||
transactionService = (TransactionService) applicationContext.getBean("transactionComponent");
|
transactionService = (TransactionService) applicationContext.getBean("transactionComponent");
|
||||||
|
retryingTransactionHelper = (RetryingTransactionHelper) applicationContext.getBean("retryingTransactionHelper");
|
||||||
policyComponent = (PolicyComponent) applicationContext.getBean("policyComponent");
|
policyComponent = (PolicyComponent) applicationContext.getBean("policyComponent");
|
||||||
authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent");
|
authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent");
|
||||||
|
|
||||||
|
@@ -27,15 +27,14 @@ package org.alfresco.repo.node;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.transaction.UserTransaction;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||||
import org.alfresco.repo.dictionary.M2Model;
|
import org.alfresco.repo.dictionary.M2Model;
|
||||||
import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
|
import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
import org.alfresco.repo.transaction.TransactionUtil;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
@@ -78,6 +77,7 @@ public class ConcurrentNodeServiceTest extends TestCase
|
|||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
|
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
|
private RetryingTransactionHelper retryingTransactionHelper;
|
||||||
|
|
||||||
private NodeRef rootNodeRef;
|
private NodeRef rootNodeRef;
|
||||||
|
|
||||||
@@ -107,23 +107,24 @@ public class ConcurrentNodeServiceTest extends TestCase
|
|||||||
|
|
||||||
nodeService = (NodeService) ctx.getBean("dbNodeService");
|
nodeService = (NodeService) ctx.getBean("dbNodeService");
|
||||||
transactionService = (TransactionService) ctx.getBean("transactionComponent");
|
transactionService = (TransactionService) ctx.getBean("transactionComponent");
|
||||||
|
retryingTransactionHelper = (RetryingTransactionHelper) ctx.getBean("retryingTransactionHelper");
|
||||||
luceneFTS = (FullTextSearchIndexer) ctx.getBean("LuceneFullTextSearchIndexer");
|
luceneFTS = (FullTextSearchIndexer) ctx.getBean("LuceneFullTextSearchIndexer");
|
||||||
this.authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
|
this.authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
|
||||||
|
|
||||||
this.authenticationComponent.setSystemUserAsCurrentUser();
|
this.authenticationComponent.setSystemUserAsCurrentUser();
|
||||||
|
|
||||||
// create a first store directly
|
// create a first store directly
|
||||||
TransactionUtil.executeInUserTransaction(transactionService, new TransactionUtil.TransactionWork<Object>()
|
RetryingTransactionCallback<Object> createRootNodeCallback = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
|
public Object execute() throws Exception
|
||||||
public Object doWork() throws Exception
|
|
||||||
{
|
{
|
||||||
StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_"
|
StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_"
|
||||||
+ System.currentTimeMillis());
|
+ System.currentTimeMillis());
|
||||||
rootNodeRef = nodeService.getRootNode(storeRef);
|
rootNodeRef = nodeService.getRootNode(storeRef);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
retryingTransactionHelper.doInTransaction(createRootNodeCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -140,17 +141,17 @@ public class ConcurrentNodeServiceTest extends TestCase
|
|||||||
|
|
||||||
protected Map<QName, ChildAssociationRef> commitNodeGraph() throws Exception
|
protected Map<QName, ChildAssociationRef> commitNodeGraph() throws Exception
|
||||||
{
|
{
|
||||||
return TransactionUtil.executeInUserTransaction(transactionService,
|
RetryingTransactionCallback<Map<QName, ChildAssociationRef>> buildGraphCallback =
|
||||||
new TransactionUtil.TransactionWork<Map<QName, ChildAssociationRef>>()
|
new RetryingTransactionCallback<Map<QName, ChildAssociationRef>>()
|
||||||
{
|
{
|
||||||
|
public Map<QName, ChildAssociationRef> execute() throws Exception
|
||||||
public Map<QName, ChildAssociationRef> doWork() throws Exception
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Map<QName, ChildAssociationRef> answer = buildNodeGraph();
|
Map<QName, ChildAssociationRef> answer = buildNodeGraph();
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
return retryingTransactionHelper.doInTransaction(buildGraphCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void xtest1() throws Exception
|
public void xtest1() throws Exception
|
||||||
@@ -231,10 +232,10 @@ public class ConcurrentNodeServiceTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionUtil.executeInUserTransaction(transactionService, new TransactionUtil.TransactionWork<Object>()
|
// Test it
|
||||||
|
RetryingTransactionCallback<Object> testCallback = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
|
public Object execute() throws Exception
|
||||||
public Object doWork() throws Exception
|
|
||||||
{
|
{
|
||||||
// There are two nodes at the base level in each test
|
// There are two nodes at the base level in each test
|
||||||
assertEquals(2 * ((COUNT * REPEATS) + 1), nodeService.getChildAssocs(rootNodeRef).size());
|
assertEquals(2 * ((COUNT * REPEATS) + 1), nodeService.getChildAssocs(rootNodeRef).size());
|
||||||
@@ -276,9 +277,8 @@ public class ConcurrentNodeServiceTest extends TestCase
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
});
|
retryingTransactionHelper.doInTransaction(testCallback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -40,8 +40,7 @@ import org.alfresco.repo.domain.Node;
|
|||||||
import org.alfresco.repo.domain.NodeStatus;
|
import org.alfresco.repo.domain.NodeStatus;
|
||||||
import org.alfresco.repo.node.BaseNodeServiceTest;
|
import org.alfresco.repo.node.BaseNodeServiceTest;
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||||
import org.alfresco.repo.transaction.TransactionUtil;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
|
|
||||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
@@ -143,9 +142,9 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
endTransaction();
|
endTransaction();
|
||||||
|
|
||||||
// change property - check status
|
// change property - check status
|
||||||
TransactionWork<Object> changePropertiesWork = new TransactionWork<Object>()
|
RetryingTransactionCallback<Object> changePropertiesWork = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork()
|
public Object execute()
|
||||||
{
|
{
|
||||||
nodeService.setProperty(n6Ref, ContentModel.PROP_CREATED, new Date());
|
nodeService.setProperty(n6Ref, ContentModel.PROP_CREATED, new Date());
|
||||||
return null;
|
return null;
|
||||||
@@ -154,9 +153,9 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
executeAndCheck(n6Ref, changePropertiesWork);
|
executeAndCheck(n6Ref, changePropertiesWork);
|
||||||
|
|
||||||
// add an aspect
|
// add an aspect
|
||||||
TransactionWork<Object> addAspectWork = new TransactionWork<Object>()
|
RetryingTransactionCallback<Object> addAspectWork = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork()
|
public Object execute()
|
||||||
{
|
{
|
||||||
nodeService.addAspect(n6Ref, ASPECT_QNAME_TEST_MARKER, null);
|
nodeService.addAspect(n6Ref, ASPECT_QNAME_TEST_MARKER, null);
|
||||||
return null;
|
return null;
|
||||||
@@ -165,9 +164,9 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
executeAndCheck(n6Ref, addAspectWork);
|
executeAndCheck(n6Ref, addAspectWork);
|
||||||
|
|
||||||
// remove an aspect
|
// remove an aspect
|
||||||
TransactionWork<Object> removeAspectWork = new TransactionWork<Object>()
|
RetryingTransactionCallback<Object> removeAspectWork = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork()
|
public Object execute()
|
||||||
{
|
{
|
||||||
nodeService.removeAspect(n6Ref, ASPECT_QNAME_TEST_MARKER);
|
nodeService.removeAspect(n6Ref, ASPECT_QNAME_TEST_MARKER);
|
||||||
return null;
|
return null;
|
||||||
@@ -176,9 +175,9 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
executeAndCheck(n6Ref, removeAspectWork);
|
executeAndCheck(n6Ref, removeAspectWork);
|
||||||
|
|
||||||
// move the node
|
// move the node
|
||||||
TransactionWork<Object> moveNodeWork = new TransactionWork<Object>()
|
RetryingTransactionCallback<Object> moveNodeWork = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork()
|
public Object execute()
|
||||||
{
|
{
|
||||||
nodeService.moveNode(
|
nodeService.moveNode(
|
||||||
n6Ref,
|
n6Ref,
|
||||||
@@ -191,9 +190,9 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
executeAndCheck(n6Ref, moveNodeWork);
|
executeAndCheck(n6Ref, moveNodeWork);
|
||||||
|
|
||||||
// delete the node
|
// delete the node
|
||||||
TransactionWork<Object> deleteNodeWork = new TransactionWork<Object>()
|
RetryingTransactionCallback<Object> deleteNodeWork = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork()
|
public Object execute()
|
||||||
{
|
{
|
||||||
nodeService.deleteNode(n6Ref);
|
nodeService.deleteNode(n6Ref);
|
||||||
return null;
|
return null;
|
||||||
@@ -202,9 +201,9 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
executeAndCheck(n6Ref, deleteNodeWork);
|
executeAndCheck(n6Ref, deleteNodeWork);
|
||||||
|
|
||||||
// check cascade-deleted nodes
|
// check cascade-deleted nodes
|
||||||
TransactionWork<Object> checkCascadeWork = new TransactionWork<Object>()
|
RetryingTransactionCallback<Object> checkCascadeCallback = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork()
|
public Object execute()
|
||||||
{
|
{
|
||||||
// check n6
|
// check n6
|
||||||
NodeStatus n6Status = nodeDaoService.getNodeStatus(n6Ref, false);
|
NodeStatus n6Status = nodeDaoService.getNodeStatus(n6Ref, false);
|
||||||
@@ -221,12 +220,12 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TransactionUtil.executeInUserTransaction(txnService, checkCascadeWork);
|
retryingTransactionHelper.doInTransaction(checkCascadeCallback);
|
||||||
|
|
||||||
// check node recreation
|
// check node recreation
|
||||||
TransactionWork<Object> checkRecreateWork = new TransactionWork<Object>()
|
RetryingTransactionCallback<Object> checkRecreateCallback = new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork()
|
public Object execute()
|
||||||
{
|
{
|
||||||
properties.put(ContentModel.PROP_STORE_PROTOCOL, n6Ref.getStoreRef().getProtocol());
|
properties.put(ContentModel.PROP_STORE_PROTOCOL, n6Ref.getStoreRef().getProtocol());
|
||||||
properties.put(ContentModel.PROP_STORE_IDENTIFIER, n6Ref.getStoreRef().getIdentifier());
|
properties.put(ContentModel.PROP_STORE_IDENTIFIER, n6Ref.getStoreRef().getIdentifier());
|
||||||
@@ -242,10 +241,10 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TransactionUtil.executeInUserTransaction(txnService, checkRecreateWork);
|
retryingTransactionHelper.doInTransaction(checkRecreateCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeAndCheck(NodeRef nodeRef, TransactionWork<Object> work) throws Throwable
|
private void executeAndCheck(NodeRef nodeRef, RetryingTransactionCallback<Object> callback) throws Throwable
|
||||||
{
|
{
|
||||||
UserTransaction txn = txnService.getUserTransaction();
|
UserTransaction txn = txnService.getUserTransaction();
|
||||||
txn.begin();
|
txn.begin();
|
||||||
@@ -257,7 +256,7 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
assertNotSame(currentTxnId, currentStatus.getChangeTxnId());
|
assertNotSame(currentTxnId, currentStatus.getChangeTxnId());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
work.doWork();
|
callback.execute();
|
||||||
// get the status
|
// get the status
|
||||||
NodeRef.Status newStatus = nodeService.getNodeStatus(nodeRef);
|
NodeRef.Status newStatus = nodeService.getNodeStatus(nodeRef);
|
||||||
assertNotNull(newStatus);
|
assertNotNull(newStatus);
|
||||||
@@ -362,4 +361,20 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
|||||||
// Get it again
|
// Get it again
|
||||||
nodeService.getPrimaryParent(n8Ref);
|
nodeService.getPrimaryParent(n8Ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It would appear that an issue has arisen with creating and deleting nodes
|
||||||
|
* in the same transaction.
|
||||||
|
*/
|
||||||
|
public void testInTransactionCreateAndDelete() throws Exception
|
||||||
|
{
|
||||||
|
// Create a node
|
||||||
|
NodeRef nodeRef = nodeService.createNode(
|
||||||
|
rootNodeRef,
|
||||||
|
ASSOC_TYPE_QNAME_TEST_CHILDREN,
|
||||||
|
QName.createQName(NAMESPACE, this.getName()),
|
||||||
|
TYPE_QNAME_TEST_CONTENT).getChildRef();
|
||||||
|
// Delete the node
|
||||||
|
nodeService.deleteNode(nodeRef);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,7 @@ import java.util.Collection;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
@@ -72,13 +73,17 @@ import org.alfresco.util.GUID;
|
|||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.ObjectDeletedException;
|
import org.hibernate.ObjectDeletedException;
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.exception.LockAcquisitionException;
|
||||||
|
import org.springframework.dao.ConcurrencyFailureException;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.dao.DeadlockLoserDataAccessException;
|
||||||
import org.springframework.orm.hibernate3.HibernateCallback;
|
import org.springframework.orm.hibernate3.HibernateCallback;
|
||||||
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
||||||
|
|
||||||
@@ -94,6 +99,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
private static final String QUERY_GET_PRIMARY_CHILD_NODE_STATUSES = "node.GetPrimaryChildNodeStatuses";
|
private static final String QUERY_GET_PRIMARY_CHILD_NODE_STATUSES = "node.GetPrimaryChildNodeStatuses";
|
||||||
private static final String QUERY_GET_CHILD_ASSOCS = "node.GetChildAssocs";
|
private static final String QUERY_GET_CHILD_ASSOCS = "node.GetChildAssocs";
|
||||||
private static final String QUERY_GET_CHILD_ASSOCS_BY_ALL = "node.GetChildAssocsByAll";
|
private static final String QUERY_GET_CHILD_ASSOCS_BY_ALL = "node.GetChildAssocsByAll";
|
||||||
|
private static final String QUERY_GET_CHILD_ASSOC_BY_NAME = "node.GetChildAssocByShortName";
|
||||||
private static final String QUERY_GET_CHILD_ASSOC_BY_TYPE_AND_NAME = "node.GetChildAssocByTypeAndName";
|
private static final String QUERY_GET_CHILD_ASSOC_BY_TYPE_AND_NAME = "node.GetChildAssocByTypeAndName";
|
||||||
private static final String QUERY_GET_CHILD_ASSOC_REFS = "node.GetChildAssocRefs";
|
private static final String QUERY_GET_CHILD_ASSOC_REFS = "node.GetChildAssocRefs";
|
||||||
private static final String QUERY_GET_CHILD_ASSOC_REFS_BY_QNAME = "node.GetChildAssocRefsByQName";
|
private static final String QUERY_GET_CHILD_ASSOC_REFS_BY_QNAME = "node.GetChildAssocRefsByQName";
|
||||||
@@ -105,12 +111,16 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress";
|
private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress";
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.class);
|
private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.class);
|
||||||
|
private static Log loggerChildAssoc = LogFactory.getLog(HibernateNodeDaoServiceImpl.class.getName() + ".ChildAssoc");
|
||||||
|
|
||||||
/** a uuid identifying this unique instance */
|
/** a uuid identifying this unique instance */
|
||||||
private final String uuid;
|
private final String uuid;
|
||||||
|
/** the number of lock retries against the parent node to ensure child uniqueness */
|
||||||
|
private int maxLockRetries;
|
||||||
|
|
||||||
private static TransactionAwareSingleton<Long> serverIdSingleton = new TransactionAwareSingleton<Long>();
|
private static TransactionAwareSingleton<Long> serverIdSingleton = new TransactionAwareSingleton<Long>();
|
||||||
private final String ipAddress;
|
private final String ipAddress;
|
||||||
|
private Random randomWaitTime;
|
||||||
|
|
||||||
/** used for debugging */
|
/** used for debugging */
|
||||||
private Set<String> changeTxnIdSet;
|
private Set<String> changeTxnIdSet;
|
||||||
@@ -121,6 +131,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
public HibernateNodeDaoServiceImpl()
|
public HibernateNodeDaoServiceImpl()
|
||||||
{
|
{
|
||||||
this.uuid = GUID.generate();
|
this.uuid = GUID.generate();
|
||||||
|
this.maxLockRetries = 20;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ipAddress = InetAddress.getLocalHost().getHostAddress();
|
ipAddress = InetAddress.getLocalHost().getHostAddress();
|
||||||
@@ -129,6 +140,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
{
|
{
|
||||||
throw new AlfrescoRuntimeException("Failed to get server IP address", e);
|
throw new AlfrescoRuntimeException("Failed to get server IP address", e);
|
||||||
}
|
}
|
||||||
|
randomWaitTime = new Random(System.currentTimeMillis());
|
||||||
|
|
||||||
changeTxnIdSet = new HashSet<String>(0);
|
changeTxnIdSet = new HashSet<String>(0);
|
||||||
}
|
}
|
||||||
@@ -158,6 +170,16 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
return uuid.hashCode();
|
return uuid.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum number of retries when attempting to get a lock on a parent node
|
||||||
|
*
|
||||||
|
* @param maxLockRetries the retry count
|
||||||
|
*/
|
||||||
|
public void setMaxLockRetries(int maxLockRetries)
|
||||||
|
{
|
||||||
|
this.maxLockRetries = maxLockRetries;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets/creates the <b>server</b> instance to use for the life of this instance
|
* Gets/creates the <b>server</b> instance to use for the life of this instance
|
||||||
*/
|
*/
|
||||||
@@ -515,8 +537,8 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
nodeStatus.getTransaction().setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
|
nodeStatus.getTransaction().setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
|
||||||
// finally delete the node
|
// finally delete the node
|
||||||
getHibernateTemplate().delete(node);
|
getHibernateTemplate().delete(node);
|
||||||
// flush to ensure constraints can't be violated
|
// // flush to ensure constraints can't be violated
|
||||||
getSession().flush();
|
// getSession().flush();
|
||||||
// done
|
// done
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,13 +606,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
public void setChildNameUnique(final ChildAssoc childAssoc, String childName)
|
public void setChildNameUnique(final ChildAssoc childAssoc, String childName)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* As the Hibernate session is rendered useless when an exception is
|
* Work out if there has been any change in the name
|
||||||
* bubbled up, we go direct to the database to update the child association.
|
|
||||||
* This preserves the session and client code can catch the resulting
|
|
||||||
* exception and react to it whilst in the same transaction.
|
|
||||||
*
|
|
||||||
* We ensure that case-insensitivity is maintained by persisting
|
|
||||||
* the lowercase version of the child node name.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String childNameNew = null;
|
String childNameNew = null;
|
||||||
@@ -621,40 +637,75 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The parent node is explicitly locked. A query is then issued to ensure that there
|
||||||
|
* are no duplicates in the index on the child assoc table. The child association is
|
||||||
|
* then modified, although not directly in the database. The lock guards against other
|
||||||
|
* transactions modifying the unique index without this transaction's knowledge.
|
||||||
|
*/
|
||||||
|
final Node parentNode = childAssoc.getParent();
|
||||||
|
// if (loggerChildAssoc.isDebugEnabled())
|
||||||
|
// {
|
||||||
|
// loggerChildAssoc.debug(
|
||||||
|
// "Locking parent node for modifying child assoc: \n" +
|
||||||
|
// " Parent: " + parentNode + "\n" +
|
||||||
|
// " Child Assoc: " + childAssoc + "\n" +
|
||||||
|
// " New Name: " + childNameNew);
|
||||||
|
// }
|
||||||
|
// for (int i = 0; i < maxLockRetries; i++)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// getSession().lock(parentNode, LockMode.UPGRADE);
|
||||||
|
// // The lock was good, proceed
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// catch (LockAcquisitionException e) {}
|
||||||
|
// catch (ConcurrencyFailureException e) {}
|
||||||
|
// // We can retry after a short pause that gets potentially longer each time
|
||||||
|
// try { Thread.sleep(randomWaitTime.nextInt(500 * i + 500)); } catch (InterruptedException ee) {}
|
||||||
|
// }
|
||||||
|
// We have the lock, so issue the query to check
|
||||||
HibernateCallback callback = new HibernateCallback()
|
HibernateCallback callback = new HibernateCallback()
|
||||||
{
|
{
|
||||||
public Object doInHibernate(Session session)
|
public Object doInHibernate(Session session)
|
||||||
{
|
{
|
||||||
session.flush();
|
|
||||||
Query query = session
|
Query query = session
|
||||||
.getNamedQuery(HibernateNodeDaoServiceImpl.UPDATE_SET_CHILD_ASSOC_NAME)
|
.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_BY_NAME)
|
||||||
.setString("newName", childNameNewShort)
|
.setLong("parentId", parentNode.getId())
|
||||||
.setLong("newNameCrc", childNameNewCrc)
|
.setParameter("childNodeName", childNameNewShort)
|
||||||
.setLong("childAssocId", childAssoc.getId());
|
.setLong("childNodeNameCrc", childNameNewCrc);
|
||||||
return (Integer) query.executeUpdate();
|
return query.uniqueResult();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try
|
ChildAssoc childAssocExisting = (ChildAssoc) getHibernateTemplate().execute(callback);
|
||||||
|
if (childAssocExisting != null)
|
||||||
{
|
{
|
||||||
Integer count = (Integer) getHibernateTemplate().execute(callback);
|
// There is already an entity
|
||||||
// refresh the entity directly
|
if (loggerChildAssoc.isDebugEnabled())
|
||||||
if (count.intValue() == 0)
|
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
loggerChildAssoc.debug(
|
||||||
{
|
"Duplicate child association detected: \n" +
|
||||||
logger.debug("ChildAssoc not updated: " + childAssoc.getId());
|
" Child Assoc: " + childAssoc + "\n" +
|
||||||
|
" Existing Child Assoc: " + childName);
|
||||||
}
|
}
|
||||||
|
throw new DuplicateChildNodeNameException(
|
||||||
|
parentNode.getNodeRef(),
|
||||||
|
childAssoc.getTypeQName(),
|
||||||
|
childName);
|
||||||
}
|
}
|
||||||
else
|
// We got past that, so we can just update the entity and know that no other transaction
|
||||||
|
// can lock the parent.
|
||||||
|
childAssoc.setChildNodeName(childNameNewShort);
|
||||||
|
childAssoc.setChildNodeNameCrc(childNameNewCrc);
|
||||||
|
|
||||||
|
// Done
|
||||||
|
if (loggerChildAssoc.isDebugEnabled())
|
||||||
{
|
{
|
||||||
getHibernateTemplate().refresh(childAssoc);
|
loggerChildAssoc.debug(
|
||||||
}
|
"Updated child association: \n" +
|
||||||
}
|
" Parent: " + parentNode + "\n" +
|
||||||
catch (DataIntegrityViolationException e)
|
" Child Assoc: " + childAssoc);
|
||||||
{
|
|
||||||
NodeRef parentNodeRef = childAssoc.getParent().getNodeRef();
|
|
||||||
QName assocTypeQName = childAssoc.getTypeQName();
|
|
||||||
throw new DuplicateChildNodeNameException(parentNodeRef, assocTypeQName, childName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -868,9 +919,9 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (loggerChildAssoc.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug(
|
loggerChildAssoc.debug(
|
||||||
"Deleting parent-child association " + assoc.getId() +
|
"Deleting parent-child association " + assoc.getId() +
|
||||||
(cascade ? " with" : " without") + " cascade:" +
|
(cascade ? " with" : " without") + " cascade:" +
|
||||||
assoc.getParent().getId() + " -> " + assoc.getChild().getId());
|
assoc.getParent().getId() + " -> " + assoc.getChild().getId());
|
||||||
@@ -894,10 +945,10 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
* duplicate call will be received to do this
|
* duplicate call will be received to do this
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
//
|
||||||
// To ensure the validity of the constraint enforcement by the database,
|
// // To ensure the validity of the constraint enforcement by the database,
|
||||||
// we have to flush here
|
// // we have to flush here. It is possible to delete and recreate the instance
|
||||||
getSession().flush();
|
// getSession().flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1117,9 +1168,9 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
{
|
{
|
||||||
// Remove instance
|
// Remove instance
|
||||||
getHibernateTemplate().delete(assoc);
|
getHibernateTemplate().delete(assoc);
|
||||||
// Flush to ensure that the database constraints aren't violated if the assoc
|
// // Flush to ensure that the database constraints aren't violated if the assoc
|
||||||
// is recreated in the transaction
|
// // is recreated in the transaction
|
||||||
getSession().flush();
|
// getSession().flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Serializable> getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition)
|
public List<Serializable> getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition)
|
||||||
|
@@ -136,9 +136,6 @@ public class SessionSizeManagementTest extends BaseNodeServiceTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
createNodes(nodeService, LOAD_COUNT, true);
|
createNodes(nodeService, LOAD_COUNT, true);
|
||||||
// Check the session size
|
|
||||||
int entityCount = getSession().getStatistics().getEntityCount();
|
|
||||||
assertTrue("Manual flush: Entity count should be less than " + LOAD_COUNT, entityCount < LOAD_COUNT);
|
|
||||||
|
|
||||||
// Now flush integrity to be sure things are not broken
|
// Now flush integrity to be sure things are not broken
|
||||||
AlfrescoTransactionSupport.flush();
|
AlfrescoTransactionSupport.flush();
|
||||||
|
@@ -50,6 +50,7 @@ import org.alfresco.repo.dictionary.DictionaryDAO;
|
|||||||
import org.alfresco.repo.dictionary.DictionaryNamespaceComponent;
|
import org.alfresco.repo.dictionary.DictionaryNamespaceComponent;
|
||||||
import org.alfresco.repo.dictionary.M2Model;
|
import org.alfresco.repo.dictionary.M2Model;
|
||||||
import org.alfresco.repo.dictionary.NamespaceDAOImpl;
|
import org.alfresco.repo.dictionary.NamespaceDAOImpl;
|
||||||
|
import org.alfresco.repo.domain.hibernate.SessionSizeResourceManager;
|
||||||
import org.alfresco.repo.node.BaseNodeServiceTest;
|
import org.alfresco.repo.node.BaseNodeServiceTest;
|
||||||
import org.alfresco.repo.search.MLAnalysisMode;
|
import org.alfresco.repo.search.MLAnalysisMode;
|
||||||
import org.alfresco.repo.search.QueryParameterDefImpl;
|
import org.alfresco.repo.search.QueryParameterDefImpl;
|
||||||
@@ -59,6 +60,8 @@ import org.alfresco.repo.search.results.ChildAssocRefResultSet;
|
|||||||
import org.alfresco.repo.search.results.DetachedResultSet;
|
import org.alfresco.repo.search.results.DetachedResultSet;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||||
@@ -67,7 +70,6 @@ import org.alfresco.service.cmr.repository.ContentData;
|
|||||||
import org.alfresco.service.cmr.repository.ContentService;
|
import org.alfresco.service.cmr.repository.ContentService;
|
||||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||||
import org.alfresco.service.cmr.repository.MLText;
|
import org.alfresco.service.cmr.repository.MLText;
|
||||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.repository.Path;
|
import org.alfresco.service.cmr.repository.Path;
|
||||||
@@ -120,6 +122,7 @@ public class ADMLuceneTest extends TestCase
|
|||||||
QName aspectWithChildren = QName.createQName(TEST_NAMESPACE, "aspectWithChildren");
|
QName aspectWithChildren = QName.createQName(TEST_NAMESPACE, "aspectWithChildren");
|
||||||
|
|
||||||
TransactionService transactionService;
|
TransactionService transactionService;
|
||||||
|
RetryingTransactionHelper retryingTransactionHelper;
|
||||||
|
|
||||||
NodeService nodeService;
|
NodeService nodeService;
|
||||||
|
|
||||||
@@ -205,6 +208,8 @@ public class ADMLuceneTest extends TestCase
|
|||||||
indexerAndSearcher = (LuceneIndexerAndSearcher) ctx.getBean("admLuceneIndexerAndSearcherFactory");
|
indexerAndSearcher = (LuceneIndexerAndSearcher) ctx.getBean("admLuceneIndexerAndSearcherFactory");
|
||||||
((AbstractLuceneIndexerAndSearcherFactory)indexerAndSearcher).setMaxAtomicTransformationTime(1000000);
|
((AbstractLuceneIndexerAndSearcherFactory)indexerAndSearcher).setMaxAtomicTransformationTime(1000000);
|
||||||
transactionService = (TransactionService) ctx.getBean("transactionComponent");
|
transactionService = (TransactionService) ctx.getBean("transactionComponent");
|
||||||
|
retryingTransactionHelper = (RetryingTransactionHelper) ctx.getBean("retryingTransactionHelper");
|
||||||
|
|
||||||
serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
||||||
|
|
||||||
namespaceDao = (NamespaceDAOImpl) ctx.getBean("namespaceDAO");
|
namespaceDao = (NamespaceDAOImpl) ctx.getBean("namespaceDAO");
|
||||||
@@ -1030,8 +1035,12 @@ public class ADMLuceneTest extends TestCase
|
|||||||
assertEquals(1, results.length());
|
assertEquals(1, results.length());
|
||||||
results.close();
|
results.close();
|
||||||
|
|
||||||
UserTransaction tx1 = transactionService.getUserTransaction();
|
RetryingTransactionCallback<Object> createAndDeleteCallback = new RetryingTransactionCallback<Object>()
|
||||||
tx1.begin();
|
{
|
||||||
|
public Object execute() throws Throwable
|
||||||
|
{
|
||||||
|
// Disable resource management
|
||||||
|
SessionSizeResourceManager.setDisableInTransaction();
|
||||||
for (int i = 0; i < 100; i++)
|
for (int i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
HashSet<ChildAssociationRef> refs = new HashSet<ChildAssociationRef>();
|
HashSet<ChildAssociationRef> refs = new HashSet<ChildAssociationRef>();
|
||||||
@@ -1046,9 +1055,11 @@ public class ADMLuceneTest extends TestCase
|
|||||||
{
|
{
|
||||||
nodeService.deleteNode(car.getChildRef());
|
nodeService.deleteNode(car.getChildRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
tx1.commit();
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
retryingTransactionHelper.doInTransaction(createAndDeleteCallback);
|
||||||
|
|
||||||
UserTransaction tx3 = transactionService.getUserTransaction();
|
UserTransaction tx3 = transactionService.getUserTransaction();
|
||||||
tx3.begin();
|
tx3.begin();
|
||||||
@@ -1134,8 +1145,10 @@ public class ADMLuceneTest extends TestCase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
System.out.println("Start " + this.getName());
|
System.out.println("Start " + this.getName());
|
||||||
UserTransaction tx1 = transactionService.getUserTransaction();
|
RetryingTransactionCallback<Object> createAndDeleteCallback = new RetryingTransactionCallback<Object>()
|
||||||
tx1.begin();
|
{
|
||||||
|
public Object execute() throws Throwable
|
||||||
|
{
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
HashSet<ChildAssociationRef> refs = new HashSet<ChildAssociationRef>();
|
HashSet<ChildAssociationRef> refs = new HashSet<ChildAssociationRef>();
|
||||||
@@ -1150,13 +1163,16 @@ public class ADMLuceneTest extends TestCase
|
|||||||
{
|
{
|
||||||
nodeService.deleteNode(car.getChildRef());
|
nodeService.deleteNode(car.getChildRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
tx1.commit();
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
retryingTransactionHelper.doInTransaction(createAndDeleteCallback);
|
||||||
System.out.println("End " + this.getName());
|
System.out.println("End " + this.getName());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
System.out.println("End " + this.getName() + " with error " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@@ -1,5 +1,26 @@
|
|||||||
/**
|
/*
|
||||||
|
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
* As a special exception to the terms and conditions of version 2.0 of
|
||||||
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||||
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||||
|
* FLOSS exception. You should have recieved a copy of the text describing
|
||||||
|
* the FLOSS exception, and it is also available here:
|
||||||
|
* http://www.alfresco.com/legal/licensing"
|
||||||
*/
|
*/
|
||||||
package org.alfresco.repo.transaction;
|
package org.alfresco.repo.transaction;
|
||||||
|
|
||||||
@@ -10,6 +31,7 @@ import javax.transaction.SystemException;
|
|||||||
import javax.transaction.UserTransaction;
|
import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.error.ExceptionStackUtil;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.hibernate.StaleObjectStateException;
|
import org.hibernate.StaleObjectStateException;
|
||||||
@@ -21,12 +43,27 @@ import org.springframework.dao.DeadlockLoserDataAccessException;
|
|||||||
* A helper that runs a unit of work inside a UserTransaction,
|
* A helper that runs a unit of work inside a UserTransaction,
|
||||||
* transparently retrying the unit of work if the cause of
|
* transparently retrying the unit of work if the cause of
|
||||||
* failure is an optimistic locking or deadlock condition.
|
* failure is an optimistic locking or deadlock condition.
|
||||||
|
*
|
||||||
* @author britt
|
* @author britt
|
||||||
*/
|
*/
|
||||||
public class RetryingTransactionHelper
|
public class RetryingTransactionHelper
|
||||||
{
|
{
|
||||||
private static Logger fgLogger = Logger.getLogger(RetryingTransactionHelper.class);
|
private static Logger fgLogger = Logger.getLogger(RetryingTransactionHelper.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exceptions that trigger retries.
|
||||||
|
*/
|
||||||
|
private static final Class[] RETRY_EXCEPTIONS;
|
||||||
|
static
|
||||||
|
{
|
||||||
|
RETRY_EXCEPTIONS = new Class[] {
|
||||||
|
ConcurrencyFailureException.class,
|
||||||
|
DeadlockLoserDataAccessException.class,
|
||||||
|
StaleObjectStateException.class,
|
||||||
|
LockAcquisitionException.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to the TransactionService instance.
|
* Reference to the TransactionService instance.
|
||||||
*/
|
*/
|
||||||
@@ -46,9 +83,15 @@ public class RetryingTransactionHelper
|
|||||||
* Callback interface
|
* Callback interface
|
||||||
* @author britt
|
* @author britt
|
||||||
*/
|
*/
|
||||||
public interface Callback
|
public interface RetryingTransactionCallback<Result>
|
||||||
{
|
{
|
||||||
public Object execute();
|
/**
|
||||||
|
* Perform a unit of transactional work.
|
||||||
|
*
|
||||||
|
* @return Return the result of the unit of work
|
||||||
|
* @throws Throwable This can be anything and will guarantee either a retry or a rollback
|
||||||
|
*/
|
||||||
|
public Result execute() throws Throwable;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,11 +124,53 @@ public class RetryingTransactionHelper
|
|||||||
* because of an error not the result of an optimistic locking failure,
|
* because of an error not the result of an optimistic locking failure,
|
||||||
* or a deadlock loser failure, or until a maximum number of retries have
|
* or a deadlock loser failure, or until a maximum number of retries have
|
||||||
* been attempted.
|
* been attempted.
|
||||||
|
* <p>
|
||||||
|
* If there is already an active transaction, then the callback is merely
|
||||||
|
* executed and any retry logic is left to the caller. The transaction
|
||||||
|
* will attempt to be read-write.
|
||||||
|
*
|
||||||
|
* @param cb The callback containing the unit of work.
|
||||||
|
* @return Returns the result of the unit of work.
|
||||||
|
*/
|
||||||
|
public <R> R doInTransaction(RetryingTransactionCallback<R> cb)
|
||||||
|
{
|
||||||
|
return doInTransaction(cb, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a callback in a transaction until it succeeds, fails
|
||||||
|
* because of an error not the result of an optimistic locking failure,
|
||||||
|
* or a deadlock loser failure, or until a maximum number of retries have
|
||||||
|
* been attempted.
|
||||||
|
* <p>
|
||||||
|
* If there is already an active transaction, then the callback is merely
|
||||||
|
* executed and any retry logic is left to the caller.
|
||||||
|
*
|
||||||
* @param cb The callback containing the unit of work.
|
* @param cb The callback containing the unit of work.
|
||||||
* @param readOnly Whether this is a read only transaction.
|
* @param readOnly Whether this is a read only transaction.
|
||||||
* @return The result of the unit of work.
|
* @return Returns the result of the unit of work.
|
||||||
*/
|
*/
|
||||||
public Object doInTransaction(Callback cb, boolean readOnly)
|
public <R> R doInTransaction(RetryingTransactionCallback<R> cb, boolean readOnly)
|
||||||
|
{
|
||||||
|
return doInTransaction(cb, readOnly, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a callback in a transaction until it succeeds, fails
|
||||||
|
* because of an error not the result of an optimistic locking failure,
|
||||||
|
* or a deadlock loser failure, or until a maximum number of retries have
|
||||||
|
* been attempted.
|
||||||
|
* <p>
|
||||||
|
* It is possible to force a new transaction to be created or to partake in
|
||||||
|
* any existing transaction.
|
||||||
|
*
|
||||||
|
* @param cb The callback containing the unit of work.
|
||||||
|
* @param readOnly Whether this is a read only transaction.
|
||||||
|
* @param newTransaction <tt>true</tt> to force a new transaction or
|
||||||
|
* <tt>false</tt> to partake in any existing transaction.
|
||||||
|
* @return Returns the result of the unit of work.
|
||||||
|
*/
|
||||||
|
public <R> R doInTransaction(RetryingTransactionCallback<R> cb, boolean readOnly, boolean newTransaction)
|
||||||
{
|
{
|
||||||
// Track the last exception caught, so that we
|
// Track the last exception caught, so that we
|
||||||
// can throw it if we run out of retries.
|
// can throw it if we run out of retries.
|
||||||
@@ -95,8 +180,15 @@ public class RetryingTransactionHelper
|
|||||||
UserTransaction txn = null;
|
UserTransaction txn = null;
|
||||||
boolean isNew = false;
|
boolean isNew = false;
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
if (newTransaction)
|
||||||
|
{
|
||||||
|
txn = fTxnService.getNonPropagatingUserTransaction();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
txn = fTxnService.getUserTransaction(readOnly);
|
txn = fTxnService.getUserTransaction(readOnly);
|
||||||
|
}
|
||||||
// Do we need to handle transaction demarcation. If
|
// Do we need to handle transaction demarcation. If
|
||||||
// no, we cannot do retries, that will be up to the containing
|
// no, we cannot do retries, that will be up to the containing
|
||||||
// transaction.
|
// transaction.
|
||||||
@@ -106,7 +198,7 @@ public class RetryingTransactionHelper
|
|||||||
txn.begin();
|
txn.begin();
|
||||||
}
|
}
|
||||||
// Do the work.
|
// Do the work.
|
||||||
Object result = cb.execute();
|
R result = cb.execute();
|
||||||
// Only commit if we 'own' the transaction.
|
// Only commit if we 'own' the transaction.
|
||||||
if (isNew)
|
if (isNew)
|
||||||
{
|
{
|
||||||
@@ -160,17 +252,10 @@ public class RetryingTransactionHelper
|
|||||||
}
|
}
|
||||||
lastException = (e instanceof RuntimeException) ?
|
lastException = (e instanceof RuntimeException) ?
|
||||||
(RuntimeException)e : new AlfrescoRuntimeException("Unknown Exception in Transaction.", e);
|
(RuntimeException)e : new AlfrescoRuntimeException("Unknown Exception in Transaction.", e);
|
||||||
Throwable t = e;
|
// Check if there is a cause for retrying
|
||||||
boolean shouldRetry = false;
|
Throwable retryCause = ExceptionStackUtil.getCause(e, RETRY_EXCEPTIONS);
|
||||||
while (t != null)
|
if (retryCause != null)
|
||||||
{
|
{
|
||||||
// These are the 'OK' exceptions. These mean we can retry.
|
|
||||||
if (t instanceof ConcurrencyFailureException ||
|
|
||||||
t instanceof DeadlockLoserDataAccessException ||
|
|
||||||
t instanceof StaleObjectStateException ||
|
|
||||||
t instanceof LockAcquisitionException)
|
|
||||||
{
|
|
||||||
shouldRetry = true;
|
|
||||||
// Sleep a random amount of time before retrying.
|
// Sleep a random amount of time before retrying.
|
||||||
// The sleep interval increases with the number of retries.
|
// The sleep interval increases with the number of retries.
|
||||||
try
|
try
|
||||||
@@ -181,24 +266,14 @@ public class RetryingTransactionHelper
|
|||||||
{
|
{
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
break;
|
// Try again
|
||||||
}
|
|
||||||
if (t == t.getCause())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
t = t.getCause();
|
|
||||||
}
|
|
||||||
if (shouldRetry)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// It was a 'bad' exception.
|
else
|
||||||
if (e instanceof RuntimeException)
|
|
||||||
{
|
{
|
||||||
throw (RuntimeException)e;
|
// It was a 'bad' exception.
|
||||||
|
throw lastException;
|
||||||
}
|
}
|
||||||
throw new AlfrescoRuntimeException("Exception in Transaction.", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We've worn out our welcome and retried the maximum number of times.
|
// We've worn out our welcome and retried the maximum number of times.
|
||||||
|
@@ -37,7 +37,9 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
/**
|
/**
|
||||||
* Class containing transactions helper methods and interfaces.
|
* Class containing transactions helper methods and interfaces.
|
||||||
*
|
*
|
||||||
* @author Roy Wetherall
|
* @deprecated Use a {@link RetryingTransactionHelper} instance
|
||||||
|
*
|
||||||
|
* @author Derek Hulley
|
||||||
*/
|
*/
|
||||||
public class TransactionUtil
|
public class TransactionUtil
|
||||||
{
|
{
|
||||||
@@ -48,6 +50,9 @@ public class TransactionUtil
|
|||||||
* <p>
|
* <p>
|
||||||
* This interface encapsulates a unit of work that should be done within a
|
* This interface encapsulates a unit of work that should be done within a
|
||||||
* transaction.
|
* transaction.
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
* @see RetryingTransactionHelper.RetryingTransactionCallback
|
||||||
*/
|
*/
|
||||||
public interface TransactionWork<Result>
|
public interface TransactionWork<Result>
|
||||||
{
|
{
|
||||||
@@ -74,6 +79,8 @@ public class TransactionUtil
|
|||||||
* @param transactionWork the transaction work
|
* @param transactionWork the transaction work
|
||||||
*
|
*
|
||||||
* @throws java.lang.RuntimeException if the transaction was rolled back
|
* @throws java.lang.RuntimeException if the transaction was rolled back
|
||||||
|
*
|
||||||
|
* @deprecated Use a {@link RetryingTransactionHelper} instance
|
||||||
*/
|
*/
|
||||||
public static <R> R executeInUserTransaction(
|
public static <R> R executeInUserTransaction(
|
||||||
TransactionService transactionService,
|
TransactionService transactionService,
|
||||||
@@ -91,6 +98,8 @@ public class TransactionUtil
|
|||||||
* @param readOnly true if the transaction should be read-only
|
* @param readOnly true if the transaction should be read-only
|
||||||
*
|
*
|
||||||
* @throws java.lang.RuntimeException if the transaction was rolled back
|
* @throws java.lang.RuntimeException if the transaction was rolled back
|
||||||
|
*
|
||||||
|
* @deprecated Use a {@link RetryingTransactionHelper} instance
|
||||||
*/
|
*/
|
||||||
public static <R> R executeInUserTransaction(
|
public static <R> R executeInUserTransaction(
|
||||||
TransactionService transactionService,
|
TransactionService transactionService,
|
||||||
@@ -108,6 +117,8 @@ public class TransactionUtil
|
|||||||
* @param transactionWork the transaction work
|
* @param transactionWork the transaction work
|
||||||
*
|
*
|
||||||
* @throws java.lang.RuntimeException if the transaction was rolled back
|
* @throws java.lang.RuntimeException if the transaction was rolled back
|
||||||
|
*
|
||||||
|
* @deprecated Use a {@link RetryingTransactionHelper} instance
|
||||||
*/
|
*/
|
||||||
public static <R> R executeInNonPropagatingUserTransaction(
|
public static <R> R executeInNonPropagatingUserTransaction(
|
||||||
TransactionService transactionService,
|
TransactionService transactionService,
|
||||||
@@ -125,6 +136,8 @@ public class TransactionUtil
|
|||||||
* @param readOnly true if the transaction should be read-only
|
* @param readOnly true if the transaction should be read-only
|
||||||
*
|
*
|
||||||
* @throws java.lang.RuntimeException if the transaction was rolled back
|
* @throws java.lang.RuntimeException if the transaction was rolled back
|
||||||
|
*
|
||||||
|
* @deprecated Use a {@link RetryingTransactionHelper} instance
|
||||||
*/
|
*/
|
||||||
public static <R> R executeInNonPropagatingUserTransaction(
|
public static <R> R executeInNonPropagatingUserTransaction(
|
||||||
TransactionService transactionService,
|
TransactionService transactionService,
|
||||||
|
Reference in New Issue
Block a user