Merged 5.2.N (5.2.1) to HEAD (5.2)

125039 cturlica: Merged 5.1.N (5.1.2) to 5.2.N (5.2.1)
      124939 arebegea: Merged 5.0.N (5.0.4) to 5.1.N (5.1.2)
         124889 jvonka: Merged 50N-NDB (5.0.4) to 5.0.N (5.0.4)
            124745: MNT-15211: Follow-on (note: only affects NDB) - tweaks for further repo test fixes, including:
            - FileFolderServiceImplTest.testMove


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@127774 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2016-06-03 16:08:16 +00:00
parent 0cb9bc6dc9
commit f83f196211
2 changed files with 228 additions and 174 deletions

View File

@@ -1535,12 +1535,83 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
}
final Long newChildNodeId = newChildNode.getId();
// Now update the primary parent assoc
updatePrimaryParentAssocs(primaryParentAssoc,
newParentNode,
childNode,
newChildNodeId,
childNodeName,
oldParentNodeId,
assocTypeQName,
assocQName);
// Optimize for rename case
if (!EqualsHelper.nullSafeEquals(newParentNodeId, oldParentNodeId))
{
// Check for cyclic relationships
// TODO: This adds a lot of overhead when moving hierarchies.
// While getPaths is faster, it would be better to avoid the parentAssocsCache
// completely.
getPaths(newChildNode.getNodePair(), false);
// cycleCheck(newChildNodeId);
// Update ACLs for moved tree
Long newParentAclId = newParentNode.getAclId();
accessControlListDAO.updateInheritance(newChildNodeId, oldParentAclId, newParentAclId);
}
// Done
Pair<Long, ChildAssociationRef> assocPair = getPrimaryParentAssoc(newChildNode.getId());
Pair<Long, NodeRef> nodePair = newChildNode.getNodePair();
if (isDebugEnabled)
{
logger.debug("Moved node: " + assocPair + " ... " + nodePair);
}
return new Pair<Pair<Long, ChildAssociationRef>, Pair<Long, NodeRef>>(assocPair, nodePair);
}
protected void updatePrimaryParentAssocs(
final ChildAssocEntity primaryParentAssoc,
final Node newParentNode,
final Node childNode,
final Long newChildNodeId,
final String childNodeName,
final Long oldParentNodeId,
final QName assocTypeQName,
final QName assocQName)
{
// Because we are retrying in-transaction i.e. absorbing exceptions, we need partial rollback &/or via savepoint if needed (eg. PostgreSQL)
RetryingCallback<Integer> callback = new RetryingCallback<Integer>()
{
public Integer execute() throws Throwable
{
// Because we are retrying in-transaction i.e. absorbing exceptions, we need a Savepoint
return updatePrimaryParentAssocsImpl(primaryParentAssoc,
newParentNode,
childNode,
newChildNodeId,
childNodeName,
oldParentNodeId,
assocTypeQName,
assocQName);
}
};
childAssocRetryingHelper.doWithRetry(callback);
}
protected int updatePrimaryParentAssocsImpl(
ChildAssocEntity primaryParentAssoc,
Node newParentNode,
Node childNode,
Long newChildNodeId,
String childNodeName,
Long oldParentNodeId,
QName assocTypeQName,
QName assocQName)
{
Long newParentNodeId = newParentNode.getId();
Long childNodeId = childNode.getId();
Savepoint savepoint = controlDAO.createSavepoint("DuplicateChildNodeNameException");
// We use the child node's UUID if there is no cm:name
String childNodeNameToUse = childNodeName == null ? childNode.getUuid() : childNodeName;
@@ -1587,33 +1658,6 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
e);
}
}
};
childAssocRetryingHelper.doWithRetry(callback);
// Optimize for rename case
if (!EqualsHelper.nullSafeEquals(newParentNodeId, oldParentNodeId))
{
// Check for cyclic relationships
// TODO: This adds a lot of overhead when moving hierarchies.
// While getPaths is faster, it would be better to avoid the parentAssocsCache
// completely.
getPaths(newChildNode.getNodePair(), false);
// cycleCheck(newChildNodeId);
// Update ACLs for moved tree
Long newParentAclId = newParentNode.getAclId();
accessControlListDAO.updateInheritance(newChildNodeId, oldParentAclId, newParentAclId);
}
// Done
Pair<Long, ChildAssociationRef> assocPair = getPrimaryParentAssoc(newChildNode.getId());
Pair<Long, NodeRef> nodePair = newChildNode.getNodePair();
if (isDebugEnabled)
{
logger.debug("Moved node: " + assocPair + " ... " + nodePair);
}
return new Pair<Pair<Long, ChildAssociationRef>, Pair<Long, NodeRef>>(assocPair, nodePair);
}
@Override
public boolean updateNode(Long nodeId, QName nodeTypeQName, Locale nodeLocale)
@@ -3143,7 +3187,7 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
// Index
assoc.setAssocIndex(-1);
Long assocId = newChildAssocImplInsert(assoc, assocTypeQName, childNodeName);
Long assocId = newChildAssocInsert(assoc, assocTypeQName, childNodeName);
// Persist it
assoc.setId(assocId);
@@ -3163,11 +3207,21 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
return assoc;
}
protected Long newChildAssocImplInsert(final ChildAssocEntity assoc, final QName assocTypeQName, final String childNodeName)
protected Long newChildAssocInsert(final ChildAssocEntity assoc, final QName assocTypeQName, final String childNodeName)
{
// Because we are retrying in-transaction i.e. absorbing exceptions, we need partial rollback &/or via savepoint if needed (eg. PostgreSQL)
RetryingCallback<Long> callback = new RetryingCallback<Long>()
{
public Long execute() throws Throwable
{
return newChildAssocInsertImpl(assoc, assocTypeQName, childNodeName);
}
};
Long assocId = childAssocRetryingHelper.doWithRetry(callback);
return assocId;
}
protected Long newChildAssocInsertImpl(final ChildAssocEntity assoc, final QName assocTypeQName, final String childNodeName)
{
Savepoint savepoint = controlDAO.createSavepoint("DuplicateChildNodeNameException");
try
@@ -3203,10 +3257,6 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
e);
}
}
};
Long assocId = childAssocRetryingHelper.doWithRetry(callback);
return assocId;
}
@Override
public Pair<Long, ChildAssociationRef> newChildAssoc(
@@ -3275,11 +3325,40 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
* TODO: See about pulling automatic cm:name update logic into this DAO
*/
@Override
public void setChildAssocsUniqueName(final Long childNodeId, final String childName)
public void setChildAssocsUniqueName(Long childNodeId, String childName)
{
Integer count = setChildAssocsUniqueNameImpl(childNodeId, childName);
if (count > 0)
{
// Touch the node; parent assocs are out of sync
touchNode(childNodeId, null, null, false, false, true);
}
if (isDebugEnabled)
{
logger.debug(
"Updated cm:name to parent assocs: \n" +
" Node: " + childNodeId + "\n" +
" Name: " + childName + "\n" +
" Updated: " + count);
}
}
protected int setChildAssocsUniqueNameImpl(final Long childNodeId, final String childName)
{
// Because we are retrying in-transaction i.e. absorbing exceptions, we need partial rollback &/or via savepoint if needed (eg. PostgreSQL)
RetryingCallback<Integer> callback = new RetryingCallback<Integer>()
{
public Integer execute() throws Throwable
{
return updateChildAssocUniqueNameImpl(childNodeId, childName);
}
};
return childAssocRetryingHelper.doWithRetry(callback);
}
protected int updateChildAssocUniqueNameImpl(final Long childNodeId, final String childName)
{
int total = 0;
Savepoint savepoint = controlDAO.createSavepoint("DuplicateChildNodeNameException");
@@ -3320,23 +3399,6 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
throw new DuplicateChildNodeNameException(null, null, childName, e);
}
}
};
Integer count = childAssocRetryingHelper.doWithRetry(callback);
if (count > 0)
{
// Touch the node; parent assocs are out of sync
touchNode(childNodeId, null, null, false, false, true);
}
if (isDebugEnabled)
{
logger.debug(
"Updated cm:name to parent assocs: \n" +
" Node: " + childNodeId + "\n" +
" Name: " + childName + "\n" +
" Updated: " + count);
}
}
@Override
public Pair<Long, ChildAssociationRef> getChildAssoc(Long assocId)

View File

@@ -54,7 +54,6 @@ import org.alfresco.repo.domain.node.TransactionQueryEntity;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
@@ -64,7 +63,6 @@ import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.util.Assert;
@@ -1757,12 +1755,6 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
*/
public static class MySQLClusterNDB extends MySQL
{
// eg. see
// ArchiveAndRestoreTest.*,
// LargeArchiveAndRestoreTest.testCreateAndRestore (also bumped MaxNoOfFiredTriggers from 4000 to 12000)
// DbNodeServiceImplTest.testNodeStatus
// MultilingualDocumentAspectTest.testDeleteNode
// ...
@Override
protected Long newNodeImplInsert(NodeEntity node)
{
@@ -1805,40 +1797,40 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
return id;
}
// eg. see DbNodeServiceImplTest.testDuplicateCatch
@Override
protected Long newChildAssocImplInsert(final ChildAssocEntity assoc, final QName assocTypeQName, final String childNodeName)
protected Long newChildAssocInsert(ChildAssocEntity assoc, QName assocTypeQName, String childNodeName)
{
try
{
Long id = insertChildAssoc(assoc);
return id;
}
catch (Throwable e)
{
// DuplicateChildNodeNameException implements DoNotRetryException.
// Allow real DB concurrency issues (e.g. DeadlockLoserDataAccessException) straight through for a retry
if (e instanceof ConcurrencyFailureException)
{
throw e;
// no in-txn retry / full rollback on sql exception
return newChildAssocInsertImpl(assoc, assocTypeQName, childNodeName);
}
// There are some cases - FK violations, specifically - where we DO actually want to retry.
// Detecting this is done by looking for the related FK names, 'fk_alf_cass_*' in the error message
String lowerMsg = e.getMessage().toLowerCase();
if (lowerMsg.contains("fk_alf_cass_"))
@Override
protected int setChildAssocsUniqueNameImpl(Long childNodeId, String childName)
{
throw new ConcurrencyFailureException("FK violation updating primary parent association:" + assoc, e);
// no in-txn retry / full rollback on sql exception
return updateChildAssocUniqueNameImpl(childNodeId, childName);
}
// We assume that this is from the child cm:name constraint violation
throw new DuplicateChildNodeNameException(
assoc.getParentNode().getNodeRef(),
assocTypeQName,
@Override
protected void updatePrimaryParentAssocs(
ChildAssocEntity primaryParentAssoc,
Node newParentNode,
Node childNode,
Long newChildNodeId,
String childNodeName,
Long oldParentNodeId,
QName assocTypeQName,
QName assocQName)
{
// no in-txn retry / full rollback on sql exception
updatePrimaryParentAssocsImpl(primaryParentAssoc,
newParentNode,
childNode,
newChildNodeId,
childNodeName,
e);
}
oldParentNodeId,
assocTypeQName,
assocQName);
}
}