Skip to content
This repository has been archived by the owner on Oct 27, 2020. It is now read-only.

MNT-18308 - Add flag forceAsyncAclCreation #984

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,32 @@
*/
package org.alfresco.repo.domain.permissions;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.NodeIdAndAclId;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.repo.security.permissions.AccessControlListProperties;
import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties;
import org.alfresco.repo.security.permissions.impl.AclChange;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.NodeIdAndAclId;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.repo.security.permissions.AccessControlListProperties;
import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties;
import org.alfresco.repo.security.permissions.impl.AclChange;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.ConcurrencyFailureException;

/**
Expand All @@ -74,7 +74,10 @@ public class ADMAccessControlListDAO implements AccessControlListDAO

/**maxim transaction time allowed for {@link #setFixedAcls(Long, Long, Long, Long, List, boolean, AsyncCallParameters, boolean)} */
private long fixedAclMaxTransactionTime = 10 * 1000;


/** If time fixedAclMaxTransactionTime exceeds, force ACL creation to be async if flag is set to true */
private boolean forceAsyncAclCreation = false;

public void setNodeDAO(NodeDAO nodeDAO)
{
this.nodeDAO = nodeDAO;
Expand All @@ -98,11 +101,21 @@ public void setBehaviourFilter(BehaviourFilter behaviourFilter)
public void setPreserveAuditableData(boolean preserveAuditableData)
{
this.preserveAuditableData = preserveAuditableData;
}

public void setForceAsyncAclCreation(boolean forceAsyncAclCreation)
{
this.forceAsyncAclCreation = forceAsyncAclCreation;
}

public boolean isPreserveAuditableData()
{
return preserveAuditableData;
}

public boolean isForceAsyncAclCreation()
{
return forceAsyncAclCreation;
}

public void forceCopy(NodeRef nodeRef)
Expand Down Expand Up @@ -465,45 +478,62 @@ else if (dbAcl.getAclType() == ACLType.SHARED)
*/
private boolean setFixAclPending(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes,
boolean set, boolean asyncCall, boolean propagateOnChildren)
{
// check if async call is required
if (!asyncCall)
{
// make regular method call
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, asyncCall, propagateOnChildren);
return true;
}
else
{
// check transaction time
long transactionStartTime = AlfrescoTransactionSupport.getTransactionStartTime();
long transactionTime = System.currentTimeMillis() - transactionStartTime;
{

// If we exceeded the transaction time and either call is async or system set to force acl async creation, delegate to job
if(isSubjectToAsyncAclCreation(nodeId,asyncCall)) {
// set ASPECT_PENDING_FIX_ACL aspect on node to be later on processed with FixedAclUpdater
addFixedAclPendingAspect(nodeId, sharedAclToReplace, inheritFrom);
AlfrescoTransactionSupport.bindResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY, true);

Long setInheritFrom = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_INHERIT_FROM_ACL);
Long setSharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
return false;
}

if (transactionTime < fixedAclMaxTransactionTime)
{
// make regular method call if time is under max transaction configured time
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, asyncCall, propagateOnChildren);
return true;
}
else
{
// time exceeded;
if (nodeDAO.getPrimaryChildrenAcls(nodeId).size() == 0)
{
// if node is leaf in tree hierarchy call setFixedAcls now as processing with FixedAclUpdater would be more time consuming
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, asyncCall, false);
}
else
{
// set ASPECT_PENDING_FIX_ACL aspect on node to be later on processed with FixedAclUpdater
addFixedAclPendingAspect(nodeId, sharedAclToReplace, inheritFrom);
AlfrescoTransactionSupport.bindResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY, true);
}
// stop propagating on children nodes
return false;
}
}
}
// make regular method call
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, asyncCall, propagateOnChildren);
return true;
}

/**
* MNT-18308 - Verify if we turn this ACL creation to an asynchronous process based on three parameters: if the call is already async and
* transaction time was exceeded OR if system is set to force async ACL creation when max transaction time allowed is exceeded
* even on asynchronous calls
* @param nodeId
* @param asyncCall
* @return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a valid JavaDoc. Please remove these lines.

*/
private boolean isSubjectToAsyncAclCreation(Long nodeId, boolean asyncCall) {

//If this is not an explicitly set or forced async call, it shall never go async
if (!asyncCall && !forceAsyncAclCreation) {
return false;
}

// This can be async so check the transaction time
long transactionStartTime = AlfrescoTransactionSupport.getTransactionStartTime();
long transactionTime = System.currentTimeMillis() - transactionStartTime;
boolean hasTimeExceeded = transactionTime < fixedAclMaxTransactionTime;

// Transaction time has not exceeded yet
if (!hasTimeExceeded) {
return false;
}

// It has exceeded the allowed time frame and async acl creation is set to be forced
if (forceAsyncAclCreation) {
return true;
}

// It has exceeded the allowed time frame, the call is already async and this node has children in it
if (asyncCall && nodeDAO.getPrimaryChildrenAcls(nodeId).size() > 0 ) {
return true;
}

// It is an async call and time was exceeded, but to maintain previous behaviour, we shall still process childless nodes synchronously
return false;
}

private void addFixedAclPendingAspect(Long nodeId, Long sharedAclToReplace, Long inheritFrom)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
private PolicyComponent policyComponent;
private PolicyIgnoreUtil policyIgnoreUtil;

private List<NodeRef> currentlyProcessingNodes = new ArrayList<NodeRef>();

public void setNumThreads(int numThreads)
{
this.numThreads = numThreads;
Expand Down Expand Up @@ -183,7 +185,16 @@ public List<NodeRef> execute() throws Throwable
nodeDAO.getNodesWithAspects(aspects, getNodesCallback.getMinNodeId(), null, getNodesCallback);
getNodesCallback.done();

return getNodesCallback.getNodes();
List<NodeRef> nodesWithAspects = new ArrayList<NodeRef>();

getNodesCallback.getNodes().forEach(el -> {
if(!currentlyProcessingNodes.contains(el)) {
nodesWithAspects.add(el);
currentlyProcessingNodes.add(el);
}
});

return nodesWithAspects;
}
}, false, true);
return nodes;
Expand Down Expand Up @@ -276,7 +287,8 @@ public Void doWork() throws Exception

nodeDAO.removeNodeAspects(nodeId, aspects);
nodeDAO.removeNodeProperties(nodeId, PENDING_FIX_ACL_ASPECT_PROPS);

currentlyProcessingNodes.remove(nodeRef);

if (!policyIgnoreUtil.ignorePolicy(nodeRef))
{
boolean transformedToAsyncOperation = toBoolean((Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/alfresco/dao/dao-context.xml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@
<property name="behaviourFilter" ref="policyBehaviourFilter" />
<property name="preserveAuditableData" value="${system.auditableData.ACLs}"></property>
<property name="fixedAclMaxTransactionTime" value="${system.fixedACLs.maxTransactionTime}"/>
<property name="forceAsyncAclCreation" value="${system.fixedACLsUpdater.forceAsyncAclCreation}"></property>
</bean>

<bean id="aclCrudDAO" class="org.alfresco.repo.domain.permissions.ibatis.AclCrudDAOImpl">
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/alfresco/repository.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,8 @@ system.fixedACLsUpdater.maxItemBatchSize=100
system.fixedACLsUpdater.numThreads=4
# fixedACLsUpdater cron expression - fire at midnight every day
system.fixedACLsUpdater.cronExpression=0 0 0 * * ?
# forceAsyncAclCreation - If transaction exceeds maxTransactionTime, force all remaining nodes to be updated asynchronously
system.fixedACLsUpdater.forceAsyncAclCreation=false

cmis.disable.hidden.leading.period.files=false

Expand Down
Loading