mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
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:
@@ -1535,60 +1535,16 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
||||
}
|
||||
|
||||
final Long newChildNodeId = newChildNode.getId();
|
||||
|
||||
// Now update the primary parent assoc
|
||||
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
|
||||
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;
|
||||
|
||||
try
|
||||
{
|
||||
int updated = updatePrimaryParentAssocs(
|
||||
newChildNodeId,
|
||||
newParentNodeId,
|
||||
assocTypeQName,
|
||||
assocQName,
|
||||
childNodeNameToUse);
|
||||
controlDAO.releaseSavepoint(savepoint);
|
||||
// Ensure we invalidate the name cache (the child version key might not have been 'bumped' by the last
|
||||
// 'touch')
|
||||
if (updated > 0 && primaryParentAssoc != null)
|
||||
{
|
||||
Pair<Long, QName> oldTypeQnamePair = qnameDAO.getQName(
|
||||
primaryParentAssoc.getTypeQNameId());
|
||||
if (oldTypeQnamePair != null)
|
||||
{
|
||||
childByNameCache.remove(new ChildByNameKey(oldParentNodeId, oldTypeQnamePair.getSecond(),
|
||||
primaryParentAssoc.getChildNodeName()));
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
controlDAO.rollbackToSavepoint(savepoint);
|
||||
// DuplicateChildNodeNameException implements DoNotRetryException.
|
||||
// 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_"))
|
||||
{
|
||||
throw new ConcurrencyFailureException("FK violation updating primary parent association for " + childNodeId, e);
|
||||
}
|
||||
// We assume that this is from the child cm:name constraint violation
|
||||
throw new DuplicateChildNodeNameException(
|
||||
newParentNode.getNodeRef(),
|
||||
assocTypeQName,
|
||||
childNodeName,
|
||||
e);
|
||||
}
|
||||
}
|
||||
};
|
||||
childAssocRetryingHelper.doWithRetry(callback);
|
||||
updatePrimaryParentAssocs(primaryParentAssoc,
|
||||
newParentNode,
|
||||
childNode,
|
||||
newChildNodeId,
|
||||
childNodeName,
|
||||
oldParentNodeId,
|
||||
assocTypeQName,
|
||||
assocQName);
|
||||
|
||||
// Optimize for rename case
|
||||
if (!EqualsHelper.nullSafeEquals(newParentNodeId, oldParentNodeId))
|
||||
@@ -1615,6 +1571,94 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
||||
try
|
||||
{
|
||||
int updated = updatePrimaryParentAssocs(
|
||||
newChildNodeId,
|
||||
newParentNodeId,
|
||||
assocTypeQName,
|
||||
assocQName,
|
||||
childNodeNameToUse);
|
||||
controlDAO.releaseSavepoint(savepoint);
|
||||
// Ensure we invalidate the name cache (the child version key might not have been 'bumped' by the last
|
||||
// 'touch')
|
||||
if (updated > 0 && primaryParentAssoc != null)
|
||||
{
|
||||
Pair<Long, QName> oldTypeQnamePair = qnameDAO.getQName(
|
||||
primaryParentAssoc.getTypeQNameId());
|
||||
if (oldTypeQnamePair != null)
|
||||
{
|
||||
childByNameCache.remove(new ChildByNameKey(oldParentNodeId, oldTypeQnamePair.getSecond(),
|
||||
primaryParentAssoc.getChildNodeName()));
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
controlDAO.rollbackToSavepoint(savepoint);
|
||||
// DuplicateChildNodeNameException implements DoNotRetryException.
|
||||
// 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_"))
|
||||
{
|
||||
throw new ConcurrencyFailureException("FK violation updating primary parent association for " + childNodeId, e);
|
||||
}
|
||||
// We assume that this is from the child cm:name constraint violation
|
||||
throw new DuplicateChildNodeNameException(
|
||||
newParentNode.getNodeRef(),
|
||||
assocTypeQName,
|
||||
childNodeName,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
@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,50 +3207,56 @@ 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
|
||||
{
|
||||
Savepoint savepoint = controlDAO.createSavepoint("DuplicateChildNodeNameException");
|
||||
try
|
||||
{
|
||||
Long id = insertChildAssoc(assoc);
|
||||
controlDAO.releaseSavepoint(savepoint);
|
||||
return id;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
controlDAO.rollbackToSavepoint(savepoint);
|
||||
// DuplicateChildNodeNameException implements DoNotRetryException.
|
||||
|
||||
// Allow real DB concurrency issues (e.g. DeadlockLoserDataAccessException) straight through for a retry
|
||||
if (e instanceof ConcurrencyFailureException)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
// 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_"))
|
||||
{
|
||||
throw new ConcurrencyFailureException("FK violation updating primary parent association:" + assoc, e);
|
||||
}
|
||||
|
||||
// We assume that this is from the child cm:name constraint violation
|
||||
throw new DuplicateChildNodeNameException(
|
||||
assoc.getParentNode().getNodeRef(),
|
||||
assocTypeQName,
|
||||
childNodeName,
|
||||
e);
|
||||
}
|
||||
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
|
||||
{
|
||||
Long id = insertChildAssoc(assoc);
|
||||
controlDAO.releaseSavepoint(savepoint);
|
||||
return id;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
controlDAO.rollbackToSavepoint(savepoint);
|
||||
// DuplicateChildNodeNameException implements DoNotRetryException.
|
||||
|
||||
// Allow real DB concurrency issues (e.g. DeadlockLoserDataAccessException) straight through for a retry
|
||||
if (e instanceof ConcurrencyFailureException)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
// 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_"))
|
||||
{
|
||||
throw new ConcurrencyFailureException("FK violation updating primary parent association:" + assoc, e);
|
||||
}
|
||||
|
||||
// We assume that this is from the child cm:name constraint violation
|
||||
throw new DuplicateChildNodeNameException(
|
||||
assoc.getParentNode().getNodeRef(),
|
||||
assocTypeQName,
|
||||
childNodeName,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Long, ChildAssociationRef> newChildAssoc(
|
||||
@@ -3275,53 +3325,10 @@ 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)
|
||||
{
|
||||
RetryingCallback<Integer> callback = new RetryingCallback<Integer>()
|
||||
{
|
||||
public Integer execute() throws Throwable
|
||||
{
|
||||
int total = 0;
|
||||
Savepoint savepoint = controlDAO.createSavepoint("DuplicateChildNodeNameException");
|
||||
try
|
||||
{
|
||||
for (ChildAssocEntity parentAssoc : getParentAssocsCached(childNodeId).getParentAssocs().values())
|
||||
{
|
||||
// Subtlety: We only update those associations for which name uniqueness checking is enforced.
|
||||
// Such associations have a positive CRC
|
||||
if (parentAssoc.getChildNodeNameCrc() <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Pair<Long, QName> oldTypeQnamePair = qnameDAO.getQName(parentAssoc.getTypeQNameId());
|
||||
// Ensure we invalidate the name cache (the child version key might not be 'bumped' by the next
|
||||
// 'touch')
|
||||
if (oldTypeQnamePair != null)
|
||||
{
|
||||
childByNameCache.remove(new ChildByNameKey(parentAssoc.getParentNode().getId(),
|
||||
oldTypeQnamePair.getSecond(), parentAssoc.getChildNodeName()));
|
||||
}
|
||||
int count = updateChildAssocUniqueName(parentAssoc.getId(), childName);
|
||||
if (count <= 0)
|
||||
{
|
||||
// Should not be attempting to delete a deleted node
|
||||
throw new ConcurrencyFailureException("Failed to update an existing parent association "
|
||||
+ parentAssoc.getId());
|
||||
}
|
||||
total += count;
|
||||
}
|
||||
controlDAO.releaseSavepoint(savepoint);
|
||||
return total;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
controlDAO.rollbackToSavepoint(savepoint);
|
||||
// We assume that this is from the child cm:name constraint violation
|
||||
throw new DuplicateChildNodeNameException(null, null, childName, e);
|
||||
}
|
||||
}
|
||||
};
|
||||
Integer count = childAssocRetryingHelper.doWithRetry(callback);
|
||||
Integer count = setChildAssocsUniqueNameImpl(childNodeId, childName);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
// Touch the node; parent assocs are out of sync
|
||||
@@ -3337,6 +3344,61 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
||||
" 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");
|
||||
try
|
||||
{
|
||||
for (ChildAssocEntity parentAssoc : getParentAssocsCached(childNodeId).getParentAssocs().values())
|
||||
{
|
||||
// Subtlety: We only update those associations for which name uniqueness checking is enforced.
|
||||
// Such associations have a positive CRC
|
||||
if (parentAssoc.getChildNodeNameCrc() <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Pair<Long, QName> oldTypeQnamePair = qnameDAO.getQName(parentAssoc.getTypeQNameId());
|
||||
// Ensure we invalidate the name cache (the child version key might not be 'bumped' by the next
|
||||
// 'touch')
|
||||
if (oldTypeQnamePair != null)
|
||||
{
|
||||
childByNameCache.remove(new ChildByNameKey(parentAssoc.getParentNode().getId(),
|
||||
oldTypeQnamePair.getSecond(), parentAssoc.getChildNodeName()));
|
||||
}
|
||||
int count = updateChildAssocUniqueName(parentAssoc.getId(), childName);
|
||||
if (count <= 0)
|
||||
{
|
||||
// Should not be attempting to delete a deleted node
|
||||
throw new ConcurrencyFailureException("Failed to update an existing parent association "
|
||||
+ parentAssoc.getId());
|
||||
}
|
||||
total += count;
|
||||
}
|
||||
controlDAO.releaseSavepoint(savepoint);
|
||||
return total;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
controlDAO.rollbackToSavepoint(savepoint);
|
||||
// We assume that this is from the child cm:name constraint violation
|
||||
throw new DuplicateChildNodeNameException(null, null, childName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Long, ChildAssociationRef> getChildAssoc(Long assocId)
|
||||
|
Reference in New Issue
Block a user