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);
|
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 Set<NodeRef> getUsageDeltaNodes();
|
||||||
|
|
||||||
public int deleteDeltas(NodeRef nodeRef);
|
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.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.util.GUID;
|
import org.alfresco.util.GUID;
|
||||||
import org.alfresco.util.Pair;
|
import org.alfresco.util.Pair;
|
||||||
|
import org.springframework.dao.ConcurrencyFailureException;
|
||||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
@@ -158,12 +159,12 @@ public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements Usage
|
|||||||
|
|
||||||
// execute
|
// execute
|
||||||
Integer delCount = (Integer) getHibernateTemplate().execute(callback);
|
Integer delCount = (Integer) getHibernateTemplate().execute(callback);
|
||||||
|
|
||||||
return delCount.intValue();
|
return (delCount == null ? 0 : delCount.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public long getTotalDeltaSize(NodeRef nodeRef)
|
private Object[] getTotalDeltaSizeImpl(NodeRef nodeRef)
|
||||||
{
|
{
|
||||||
final Long nodeId = getNodeIdNotNull(nodeRef);
|
final Long nodeId = getNodeIdNotNull(nodeRef);
|
||||||
HibernateCallback callback = new HibernateCallback()
|
HibernateCallback callback = new HibernateCallback()
|
||||||
@@ -176,10 +177,40 @@ public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements Usage
|
|||||||
return query.uniqueResult();
|
return query.uniqueResult();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// execute read-only tx
|
// execute read-only tx
|
||||||
Long queryResult = (Long)getHibernateTemplate().execute(callback);
|
return (Object[])getHibernateTemplate().execute(callback);
|
||||||
|
}
|
||||||
return (queryResult == null ? 0 : queryResult);
|
|
||||||
|
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)
|
public void insertDelta(NodeRef usageNodeRef, long deltaSize)
|
||||||
|
@@ -50,7 +50,7 @@
|
|||||||
<!-- Get total usage delta for a node -->
|
<!-- Get total usage delta for a node -->
|
||||||
<query name="usage.GetTotalDeltaSize">
|
<query name="usage.GetTotalDeltaSize">
|
||||||
select
|
select
|
||||||
sum(deltaSize)
|
count(deltaSize), sum(deltaSize)
|
||||||
from
|
from
|
||||||
org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage_delta
|
org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage_delta
|
||||||
where
|
where
|
||||||
|
@@ -504,7 +504,11 @@ public class ContentUsageImpl implements ContentUsageService,
|
|||||||
return (currentUsage == null ? -1 : currentUsage);
|
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);
|
ParameterCheck.mandatoryString("userName", userName);
|
||||||
|
|
||||||
@@ -518,9 +522,11 @@ public class ContentUsageImpl implements ContentUsageService,
|
|||||||
|
|
||||||
if (currentUsage != -1)
|
if (currentUsage != -1)
|
||||||
{
|
{
|
||||||
// add any deltas
|
long deltaSize = removeDeltas ? usageService.getAndRemoveTotalDeltaSize(personNodeRef) :
|
||||||
currentUsage = currentUsage + usageService.getTotalDeltaSize(personNodeRef);
|
usageService.getTotalDeltaSize(personNodeRef);
|
||||||
|
// add any deltas to the currentUsage, removing them if required
|
||||||
|
currentUsage = currentUsage + deltaSize;
|
||||||
|
|
||||||
if (currentUsage < 0)
|
if (currentUsage < 0)
|
||||||
{
|
{
|
||||||
if (logger.isWarnEnabled())
|
if (logger.isWarnEnabled())
|
||||||
|
@@ -49,6 +49,11 @@ public class UsageServiceImpl implements UsageService
|
|||||||
return usageDeltaDAO.getTotalDeltaSize(usageNodeRef);
|
return usageDeltaDAO.getTotalDeltaSize(usageNodeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef)
|
||||||
|
{
|
||||||
|
return usageDeltaDAO.getAndRemoveTotalDeltaSize(usageNodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
public Set<NodeRef> getUsageDeltaNodes()
|
public Set<NodeRef> getUsageDeltaNodes()
|
||||||
{
|
{
|
||||||
return usageDeltaDAO.getUsageDeltaNodes();
|
return usageDeltaDAO.getUsageDeltaNodes();
|
||||||
|
@@ -564,9 +564,11 @@ public class UserUsageTrackingComponent extends AbstractLifecycleBean
|
|||||||
long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef);
|
long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef);
|
||||||
if (currentUsage != -1)
|
if (currentUsage != -1)
|
||||||
{
|
{
|
||||||
// collapse the usage deltas
|
// Collapse the usage deltas
|
||||||
currentUsage = contentUsageImpl.getUserUsage(userName);
|
// Calculate and remove deltas in one go to guard against deletion of
|
||||||
usageService.deleteDeltas(personNodeRef);
|
// deltas from another transaction that have not been included in the
|
||||||
|
// calculation
|
||||||
|
currentUsage = contentUsageImpl.getUserUsage(userName, true);
|
||||||
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
|
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
|
||||||
|
|
||||||
if (logger.isTraceEnabled())
|
if (logger.isTraceEnabled())
|
||||||
|
@@ -44,7 +44,13 @@ public interface UsageService
|
|||||||
*/
|
*/
|
||||||
@NotAuditable
|
@NotAuditable
|
||||||
public long getTotalDeltaSize(NodeRef usageNodeRef);
|
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
|
* Get distinct set of usage delta nodes
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user