mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Can't reproduce the bug but spotted a race condition in UserUsageTrackingComponent that may cause this in rare circumstances. Deal with this by throwing a ConcurrencyFailureException and let the txn retry handler retry the operation. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19862 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -43,6 +43,14 @@ public interface UsageDeltaDAO
|
||||
*/
|
||||
public long getTotalDeltaSize(NodeRef usageNodeRef);
|
||||
|
||||
/**
|
||||
* Get the total delta size for a node and remove any deltas used in the calculation.
|
||||
*
|
||||
* @param nodeRef the node reference
|
||||
* @return sum of delta sizes (in bytes) - can be +ve or -ve
|
||||
*/
|
||||
public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef);
|
||||
|
||||
public Set<NodeRef> getUsageDeltaNodes();
|
||||
|
||||
public int deleteDeltas(NodeRef nodeRef);
|
||||
|
@@ -31,6 +31,7 @@ import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
@@ -158,12 +159,12 @@ public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements Usage
|
||||
|
||||
// execute
|
||||
Integer delCount = (Integer) getHibernateTemplate().execute(callback);
|
||||
|
||||
return delCount.intValue();
|
||||
|
||||
return (delCount == null ? 0 : delCount.intValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public long getTotalDeltaSize(NodeRef nodeRef)
|
||||
private Object[] getTotalDeltaSizeImpl(NodeRef nodeRef)
|
||||
{
|
||||
final Long nodeId = getNodeIdNotNull(nodeRef);
|
||||
HibernateCallback callback = new HibernateCallback()
|
||||
@@ -176,10 +177,40 @@ public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements Usage
|
||||
return query.uniqueResult();
|
||||
}
|
||||
};
|
||||
|
||||
// execute read-only tx
|
||||
Long queryResult = (Long)getHibernateTemplate().execute(callback);
|
||||
|
||||
return (queryResult == null ? 0 : queryResult);
|
||||
return (Object[])getHibernateTemplate().execute(callback);
|
||||
}
|
||||
|
||||
public long getTotalDeltaSize(NodeRef nodeRef)
|
||||
{
|
||||
Object[] result = getTotalDeltaSizeImpl(nodeRef);
|
||||
Long queryResult = (Long)result[1];
|
||||
return (queryResult == null ? 0 : queryResult.longValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Guard against deleting deltas committed by another transaction after calculating the delta sum above.
|
||||
* If the expected number of deletes is different from the actual number of deletes then deltas from
|
||||
* another committed transaction are probably being removed.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public long getAndRemoveTotalDeltaSize(NodeRef nodeRef)
|
||||
{
|
||||
Object[] result = getTotalDeltaSizeImpl(nodeRef);
|
||||
Long queryResult = (Long)result[1];
|
||||
Number deltaCount = (Number)result[0];
|
||||
|
||||
long expectedNumDeletes = deltaCount == null ? 0 : deltaCount.intValue();
|
||||
|
||||
int numDeltasRemoved = deleteDeltas(nodeRef);
|
||||
|
||||
if(expectedNumDeletes != numDeltasRemoved) {
|
||||
throw new ConcurrencyFailureException("More than expected number of usage delta deletes has occurred for node id "
|
||||
+ nodeRef.getId() + " in store " + nodeRef.getStoreRef());
|
||||
}
|
||||
|
||||
return (queryResult == null ? 0 : queryResult.longValue());
|
||||
}
|
||||
|
||||
public void insertDelta(NodeRef usageNodeRef, long deltaSize)
|
||||
|
@@ -50,7 +50,7 @@
|
||||
<!-- Get total usage delta for a node -->
|
||||
<query name="usage.GetTotalDeltaSize">
|
||||
select
|
||||
sum(deltaSize)
|
||||
count(deltaSize), sum(deltaSize)
|
||||
from
|
||||
org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage_delta
|
||||
where
|
||||
|
@@ -504,7 +504,11 @@ public class ContentUsageImpl implements ContentUsageService,
|
||||
return (currentUsage == null ? -1 : currentUsage);
|
||||
}
|
||||
|
||||
public long getUserUsage(String userName)
|
||||
public long getUserUsage(String userName) {
|
||||
return getUserUsage(userName, false);
|
||||
}
|
||||
|
||||
public long getUserUsage(String userName, boolean removeDeltas)
|
||||
{
|
||||
ParameterCheck.mandatoryString("userName", userName);
|
||||
|
||||
@@ -518,9 +522,11 @@ public class ContentUsageImpl implements ContentUsageService,
|
||||
|
||||
if (currentUsage != -1)
|
||||
{
|
||||
// add any deltas
|
||||
currentUsage = currentUsage + usageService.getTotalDeltaSize(personNodeRef);
|
||||
|
||||
long deltaSize = removeDeltas ? usageService.getAndRemoveTotalDeltaSize(personNodeRef) :
|
||||
usageService.getTotalDeltaSize(personNodeRef);
|
||||
// add any deltas to the currentUsage, removing them if required
|
||||
currentUsage = currentUsage + deltaSize;
|
||||
|
||||
if (currentUsage < 0)
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
|
@@ -49,6 +49,11 @@ public class UsageServiceImpl implements UsageService
|
||||
return usageDeltaDAO.getTotalDeltaSize(usageNodeRef);
|
||||
}
|
||||
|
||||
public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef)
|
||||
{
|
||||
return usageDeltaDAO.getAndRemoveTotalDeltaSize(usageNodeRef);
|
||||
}
|
||||
|
||||
public Set<NodeRef> getUsageDeltaNodes()
|
||||
{
|
||||
return usageDeltaDAO.getUsageDeltaNodes();
|
||||
|
@@ -564,9 +564,11 @@ public class UserUsageTrackingComponent extends AbstractLifecycleBean
|
||||
long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef);
|
||||
if (currentUsage != -1)
|
||||
{
|
||||
// collapse the usage deltas
|
||||
currentUsage = contentUsageImpl.getUserUsage(userName);
|
||||
usageService.deleteDeltas(personNodeRef);
|
||||
// Collapse the usage deltas
|
||||
// Calculate and remove deltas in one go to guard against deletion of
|
||||
// deltas from another transaction that have not been included in the
|
||||
// calculation
|
||||
currentUsage = contentUsageImpl.getUserUsage(userName, true);
|
||||
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
|
@@ -44,7 +44,13 @@ public interface UsageService
|
||||
*/
|
||||
@NotAuditable
|
||||
public long getTotalDeltaSize(NodeRef usageNodeRef);
|
||||
|
||||
|
||||
/**
|
||||
* Get sum of usage delta sizes and remove affected deltas.
|
||||
*/
|
||||
@NotAuditable
|
||||
public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef);
|
||||
|
||||
/**
|
||||
* Get distinct set of usage delta nodes
|
||||
*/
|
||||
|
Reference in New Issue
Block a user