DM user usages - 1st pass fixes (recalc and clear)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@12046 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2008-11-20 23:32:06 +00:00
parent 9451780b51
commit 16de2cc1e1
5 changed files with 177 additions and 83 deletions

View File

@@ -509,6 +509,12 @@
</constructor-arg> </constructor-arg>
</bean> </bean>
<bean id="personDaoBootstrap" class="org.alfresco.repo.security.person.PersonDaoBootstrap" >
<property name="personDaoImpl">
<ref bean="personDaoImpl"/>
</property>
</bean>
<!-- Start the quartz scheduler --> <!-- Start the quartz scheduler -->
<bean id="schedulerStarter" class="org.alfresco.util.SchedulerStarterBean" > <bean id="schedulerStarter" class="org.alfresco.util.SchedulerStarterBean" >
@@ -567,12 +573,6 @@
<property name="companyHomePath"><value>/${spaces.company_home.childname}</value></property> <property name="companyHomePath"><value>/${spaces.company_home.childname}</value></property>
</bean> </bean>
<bean id="personDaoBootstrap" class="org.alfresco.repo.security.person.PersonDaoBootstrap" >
<property name="personDaoImpl">
<ref bean="personDaoImpl"/>
</property>
</bean>
<!-- Startup Message --> <!-- Startup Message -->
<bean id="startupLog" class="org.alfresco.repo.descriptor.DescriptorStartupLog"> <bean id="startupLog" class="org.alfresco.repo.descriptor.DescriptorStartupLog">

View File

@@ -669,6 +669,20 @@
p.string_value = :propStringValue p.string_value = :propStringValue
</sql-query> </sql-query>
<query name="node.GetNodesWithCreatorAndStore">
select
node.id,
node.store.protocol,
node.store.identifier,
node.uuid
from
org.alfresco.repo.domain.hibernate.NodeImpl as node
where
node.store.protocol = :storeProtocol and
node.store.identifier = :storeIdentifier and
node.auditableProperties.auditCreator = :userName
</query>
<query name="node.GetNodesWithPropertyValuesByActualType"> <query name="node.GetNodesWithPropertyValuesByActualType">
select select
node node

View File

@@ -393,6 +393,20 @@ public interface NodeDaoService
String value, String value,
NodePropertyHandler handler); NodePropertyHandler handler);
/**
* Iterate over all nodes that have a given creator
*
* @param storeRef the store to search in
* @param userName the user to match
* @param handler the callback to use while iterating over the URLs
* @return Returns the values for the given owner
*/
@DirtySessionAnnotation(markDirty=true)
public void getNodesWithCreatorAndStore(
StoreRef storeRef,
String userName,
NodeRefQueryCallback resultsCallback);
/** /**
* Iterate over all property values for the given type definition. This will also dig out values that * Iterate over all property values for the given type definition. This will also dig out values that
* were persisted as type <b>d:any</b>. * were persisted as type <b>d:any</b>.

View File

@@ -142,6 +142,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
private static final String QUERY_GET_TARGET_ASSOCS = "node.GetTargetAssocs"; private static final String QUERY_GET_TARGET_ASSOCS = "node.GetTargetAssocs";
private static final String QUERY_GET_SOURCE_ASSOCS = "node.GetSourceAssocs"; private static final String QUERY_GET_SOURCE_ASSOCS = "node.GetSourceAssocs";
private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_STRING_AND_STORE = "node.GetNodesWithPropertyValuesByStringAndStore"; private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_STRING_AND_STORE = "node.GetNodesWithPropertyValuesByStringAndStore";
private static final String QUERY_GET_NODES_WITH_CREATOR_AND_STORE = "node.GetNodesWithCreatorAndStore";
private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE = "node.GetNodesWithPropertyValuesByActualType"; private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE = "node.GetNodesWithPropertyValuesByActualType";
private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress"; private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress";
@@ -2709,6 +2710,42 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
} }
} }
public void getNodesWithCreatorAndStore(
final StoreRef storeRef,
final String userName,
final NodeRefQueryCallback resultsCallback)
{
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
Query query = session
.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODES_WITH_CREATOR_AND_STORE)
.setString("storeProtocol", storeRef.getProtocol())
.setString("storeIdentifier", storeRef.getIdentifier())
.setString("userName", userName)
;
DirtySessionMethodInterceptor.setQueryFlushMode(session, query);
return query.scroll(ScrollMode.FORWARD_ONLY);
}
};
ScrollableResults queryResults = null;
try
{
queryResults = (ScrollableResults) getHibernateTemplate().execute(callback);
processNodeResults(queryResults, resultsCallback);
}
finally
{
if (queryResults != null)
{
queryResults.close();
}
}
// Done
}
public void getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition, NodePropertyHandler handler) public void getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition, NodePropertyHandler handler)
{ {
// get the in-database string representation of the actual type // get the in-database string representation of the actual type

View File

@@ -25,6 +25,7 @@
package org.alfresco.repo.usage; package org.alfresco.repo.usage;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -32,11 +33,11 @@ import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.node.db.NodeDaoService.NodePropertyHandler; import org.alfresco.repo.node.db.NodeDaoService.NodePropertyHandler;
import org.alfresco.repo.node.db.NodeDaoService.NodeRefQueryCallback;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.Tenant; import org.alfresco.repo.tenant.Tenant;
import org.alfresco.repo.tenant.TenantAdminService; import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.TransactionServiceImpl; import org.alfresco.repo.transaction.TransactionServiceImpl;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
@@ -47,6 +48,7 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.usage.UsageService; import org.alfresco.service.cmr.usage.UsageService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.apache.commons.lang.mutable.MutableLong; import org.apache.commons.lang.mutable.MutableLong;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -184,63 +186,102 @@ public class UserUsageTrackingComponent
} }
} }
public void clearAllUsages() private void clearAllUsages()
{ {
if (logger.isDebugEnabled()) if (logger.isInfoEnabled())
{ {
logger.debug("Disabled - clear usages for all users ..."); logger.info("Disabled - clear non-missing user usages ...");
} }
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper(); RetryingTransactionCallback<List<NodeRef>> getPersonRefs = new RetryingTransactionCallback<List<NodeRef>>()
// wrap to make the request in a transaction
RetryingTransactionCallback<Integer> clearAllUsages = new RetryingTransactionCallback<Integer>()
{ {
public Integer execute() throws Throwable public List<NodeRef> execute() throws Throwable
{ {
Set<NodeRef> allPeople = personService.getAllPeople(); Set<NodeRef> allPeople = personService.getAllPeople();
if (logger.isDebugEnabled())
{
logger.debug("Found " + allPeople.size() + " people");
}
List<NodeRef> personRefsToClear = new ArrayList<NodeRef>();
for (NodeRef personNodeRef : allPeople) for (NodeRef personNodeRef : allPeople)
{ {
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null); Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT);
usageService.deleteDeltas(personNodeRef); if (currentUsage != null)
{
personRefsToClear.add(personNodeRef);
}
} }
return allPeople.size();
if (logger.isDebugEnabled())
{
logger.debug("Found " + personRefsToClear.size() + " users to clear");
}
return personRefsToClear;
} }
}; };
// execute in txn
int count = txnHelper.doInTransaction(clearAllUsages, false); // execute in READ-ONLY txn
List<NodeRef> personRefsToClear = transactionService.getRetryingTransactionHelper().doInTransaction(getPersonRefs, true);
if (logger.isDebugEnabled())
for (NodeRef personNodeRef : personRefsToClear)
{ {
logger.debug("... cleared usages for " + count + " users"); clearUsage(personNodeRef);
}
if (logger.isInfoEnabled())
{
logger.info("... cleared non-missing usages for " + personRefsToClear.size() + " users");
} }
} }
public void calculateMissingUsages() private void clearUsage(final NodeRef personNodeRef)
{ {
if (logger.isDebugEnabled()) RetryingTransactionCallback<Integer> clearPersonUsage = new RetryingTransactionCallback<Integer>()
{ {
logger.debug("Enabled - calculate missing usages ..."); public Integer execute() throws Throwable
} {
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null);
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper(); usageService.deleteDeltas(personNodeRef);
if (logger.isTraceEnabled())
{
logger.trace("Cleared usage for person ("+ personNodeRef+")");
}
return null;
}
};
// execute in READ-WRITE txn
transactionService.getRetryingTransactionHelper().doInTransaction(clearPersonUsage, false);
}
private void calculateMissingUsages()
{
if (logger.isInfoEnabled())
{
logger.info("Enabled - calculate missing user usages ...");
}
// wrap to make the request in a transaction
RetryingTransactionCallback<Set<String>> getAllPeople = new RetryingTransactionCallback<Set<String>>() RetryingTransactionCallback<Set<String>> getAllPeople = new RetryingTransactionCallback<Set<String>>()
{ {
public Set<String> execute() throws Throwable public Set<String> execute() throws Throwable
{ {
Set<NodeRef> allPeople = personService.getAllPeople(); Set<NodeRef> allPeople = personService.getAllPeople();
if (logger.isDebugEnabled())
{
logger.debug("Found " + allPeople.size() + " people");
}
Set<String> userNames = new HashSet<String>(); Set<String> userNames = new HashSet<String>();
for (NodeRef personNodeRef : allPeople) for (NodeRef personNodeRef : allPeople)
{ {
// Cater for Lucene indexes being stale
if (!nodeService.exists(personNodeRef))
{
continue;
}
Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT); Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT);
if (currentUsage == null) if (currentUsage == null)
{ {
@@ -248,11 +289,18 @@ public class UserUsageTrackingComponent
userNames.add(userName); userNames.add(userName);
} }
} }
if (logger.isDebugEnabled())
{
logger.debug("Found " + userNames.size() + " users to recalculate");
}
return userNames; return userNames;
} }
}; };
// execute in READ-ONLY txn // execute in READ-ONLY txn
final Set<String> userNames = txnHelper.doInTransaction(getAllPeople, true); Set<String> userNames = transactionService.getRetryingTransactionHelper().doInTransaction(getAllPeople, true);
for (final String userName : userNames) for (final String userName : userNames)
{ {
@@ -266,9 +314,9 @@ public class UserUsageTrackingComponent
}, tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantAdminService.getUserDomain(userName))); }, tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantAdminService.getUserDomain(userName)));
} }
if (logger.isDebugEnabled()) if (logger.isInfoEnabled())
{ {
logger.debug("... calculated missing usages for " + userNames.size() + " users"); logger.info("... calculated missing usages for " + userNames.size() + " users");
} }
} }
@@ -279,18 +327,12 @@ public class UserUsageTrackingComponent
* *
* @param username the username to for which calcualte usages * @param username the username to for which calcualte usages
*/ */
public void recalculateUsage(final String username) private void recalculateUsage(final String username)
{ {
final RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Long> calculatePersonCurrentUsage = new RetryingTransactionCallback<Long>() RetryingTransactionCallback<Long> calculatePersonCurrentUsage = new RetryingTransactionCallback<Long>()
{ {
public Long execute() throws Throwable public Long execute() throws Throwable
{ {
// QNameEntity ownerQnameEntity = qnameDAO.getQNameEntity(ContentModel.PROP_OWNER);
// QNameEntity contentQnameEntity = qnameDAO.getQNameEntity(ContentModel.PROP_CONTENT);
//
List<String> stores = contentUsageImpl.getStores(); List<String> stores = contentUsageImpl.getStores();
final MutableLong totalUsage = new MutableLong(0L); final MutableLong totalUsage = new MutableLong(0L);
@@ -298,11 +340,11 @@ public class UserUsageTrackingComponent
{ {
final StoreRef storeRef = new StoreRef(store); final StoreRef storeRef = new StoreRef(store);
if (logger.isDebugEnabled()) if (logger.isTraceEnabled())
{ {
logger.debug("Recalc usage (" + username + ") store=" + storeRef); logger.trace("Recalc usage (" + username + ") store=" + storeRef);
} }
NodePropertyHandler propOwnerHandler = new NodePropertyHandler() NodePropertyHandler propOwnerHandler = new NodePropertyHandler()
{ {
public void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value) public void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value)
@@ -323,25 +365,19 @@ public class UserUsageTrackingComponent
}; };
nodeDaoService.getPropertyValuesByPropertyAndValue(storeRef, ContentModel.PROP_OWNER, username, propOwnerHandler); nodeDaoService.getPropertyValuesByPropertyAndValue(storeRef, ContentModel.PROP_OWNER, username, propOwnerHandler);
if (logger.isDebugEnabled()) // get nodes for which user is creator (ignore those with owner)
NodeRefQueryCallback nodeCreatorHandler = new NodeRefQueryCallback()
{ {
logger.debug("Recalc usage (" + username + ") store=" + storeRef); public boolean handle(Pair<Long, NodeRef> nodePair)
}
NodePropertyHandler propCreatorHandler = new NodePropertyHandler()
{
public void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value)
{ {
if (!nodeTypeQName.equals(ContentModel.TYPE_CONTENT)) NodeRef nodeRef = nodePair.getSecond();
{
// It is not content
return;
}
if (nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER) != null) if (nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER) != null)
{ {
// There is an owner property so we will have process this already // There is an owner property so we will have processed this already
return; return true; // continue to next node (more required)
} }
ContentData contentData = DefaultTypeConverter.INSTANCE.convert( ContentData contentData = DefaultTypeConverter.INSTANCE.convert(
ContentData.class, ContentData.class,
nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT)); nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT));
@@ -350,42 +386,38 @@ public class UserUsageTrackingComponent
long currentTotalUsage = totalUsage.longValue(); long currentTotalUsage = totalUsage.longValue();
totalUsage.setValue(currentTotalUsage + contentData.getSize()); totalUsage.setValue(currentTotalUsage + contentData.getSize());
} }
return true; // continue to next node (more required)
} }
}; };
nodeDaoService.getPropertyValuesByPropertyAndValue(storeRef, ContentModel.PROP_OWNER, username, propCreatorHandler); nodeDaoService.getNodesWithCreatorAndStore(storeRef, username, nodeCreatorHandler);
} }
if (logger.isDebugEnabled()) if (logger.isTraceEnabled())
{ {
long quotaSize = contentUsageImpl.getUserQuota(username); long quotaSize = contentUsageImpl.getUserQuota(username);
logger.debug("Recalc usage ("+ username+") totalUsage="+totalUsage+", quota="+quotaSize); logger.trace("Recalc usage ("+ username+") totalUsage="+totalUsage+", quota="+quotaSize);
} }
return totalUsage.longValue(); return totalUsage.longValue();
} }
}; };
// execute in READ-ONLY txn
final Long currentUsage = txnHelper.doInTransaction(calculatePersonCurrentUsage, true);
// wrap to make the request in a transaction // execute in READ-ONLY txn
final Long currentUsage = transactionService.getRetryingTransactionHelper().doInTransaction(calculatePersonCurrentUsage, true);
RetryingTransactionCallback<Object> updatePersonCurrentUsage = new RetryingTransactionCallback<Object>() RetryingTransactionCallback<Object> updatePersonCurrentUsage = new RetryingTransactionCallback<Object>()
{ {
public Object execute() throws Throwable public Object execute() throws Throwable
{ {
NodeRef personNodeRef = personService.getPerson(username); NodeRef personNodeRef = personService.getPerson(username);
if (!nodeService.exists(personNodeRef))
{
// Ignore
return null;
}
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage); contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
usageService.deleteDeltas(personNodeRef); usageService.deleteDeltas(personNodeRef);
return null; return null;
} }
}; };
// execute in txn // execute in READ-WRITE txn
txnHelper.doInTransaction(updatePersonCurrentUsage, false); transactionService.getRetryingTransactionHelper().doInTransaction(updatePersonCurrentUsage, false);
} }
/** /**
@@ -394,9 +426,6 @@ public class UserUsageTrackingComponent
private void collapseUsages() private void collapseUsages()
{ {
// Collapse usage deltas (if a person has initial usage set) // Collapse usage deltas (if a person has initial usage set)
final RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Object> collapseUsages = new RetryingTransactionCallback<Object>() RetryingTransactionCallback<Object> collapseUsages = new RetryingTransactionCallback<Object>()
{ {
public Object execute() throws Throwable public Object execute() throws Throwable
@@ -425,9 +454,9 @@ public class UserUsageTrackingComponent
usageService.deleteDeltas(personNodeRef); usageService.deleteDeltas(personNodeRef);
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage); contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
if (logger.isDebugEnabled()) if (logger.isTraceEnabled())
{ {
logger.debug("Collapsed usage: username=" + userName + ", usage=" + currentUsage); logger.trace("Collapsed usage: username=" + userName + ", usage=" + currentUsage);
} }
} }
else else
@@ -446,7 +475,7 @@ public class UserUsageTrackingComponent
} }
}; };
// execute in txn // execute in READ-WRITE txn
txnHelper.doInTransaction(collapseUsages, false); transactionService.getRetryingTransactionHelper().doInTransaction(collapseUsages, false);
} }
} }