From 16de2cc1e1485262d4edb9da78c49c2a679fb2e5 Mon Sep 17 00:00:00 2001 From: Jan Vonka Date: Thu, 20 Nov 2008 23:32:06 +0000 Subject: [PATCH] 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 --- config/alfresco/bootstrap-context.xml | 12 +- .../repo/domain/hibernate/Node.hbm.xml | 14 ++ .../alfresco/repo/node/db/NodeDaoService.java | 14 ++ .../HibernateNodeDaoServiceImpl.java | 37 ++++ .../usage/UserUsageTrackingComponent.java | 183 ++++++++++-------- 5 files changed, 177 insertions(+), 83 deletions(-) diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index efaf413c97..0103efcd5a 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -509,6 +509,12 @@ + + + + + + @@ -567,12 +573,6 @@ /${spaces.company_home.childname} - - - - - - diff --git a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml index bb722d7f59..363649c94e 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml @@ -669,6 +669,20 @@ p.string_value = :propStringValue + + 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 + + select node diff --git a/source/java/org/alfresco/repo/node/db/NodeDaoService.java b/source/java/org/alfresco/repo/node/db/NodeDaoService.java index 6cd22c97f4..534a26f62c 100644 --- a/source/java/org/alfresco/repo/node/db/NodeDaoService.java +++ b/source/java/org/alfresco/repo/node/db/NodeDaoService.java @@ -393,6 +393,20 @@ public interface NodeDaoService String value, 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 * were persisted as type d:any. diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java index 9f393d2394..bb7aef8f0d 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -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_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_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_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) { // get the in-database string representation of the actual type diff --git a/source/java/org/alfresco/repo/usage/UserUsageTrackingComponent.java b/source/java/org/alfresco/repo/usage/UserUsageTrackingComponent.java index 34e3b4108b..86b012ce75 100644 --- a/source/java/org/alfresco/repo/usage/UserUsageTrackingComponent.java +++ b/source/java/org/alfresco/repo/usage/UserUsageTrackingComponent.java @@ -25,6 +25,7 @@ package org.alfresco.repo.usage; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -32,11 +33,11 @@ import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.repo.node.db.NodeDaoService; 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.RunAsWork; import org.alfresco.repo.tenant.Tenant; import org.alfresco.repo.tenant.TenantAdminService; -import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.TransactionServiceImpl; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; 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.usage.UsageService; import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; import org.apache.commons.lang.mutable.MutableLong; import org.apache.commons.logging.Log; 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(); - - // wrap to make the request in a transaction - RetryingTransactionCallback clearAllUsages = new RetryingTransactionCallback() + RetryingTransactionCallback> getPersonRefs = new RetryingTransactionCallback>() { - public Integer execute() throws Throwable + public List execute() throws Throwable { Set allPeople = personService.getAllPeople(); + if (logger.isDebugEnabled()) + { + logger.debug("Found " + allPeople.size() + " people"); + } + + List personRefsToClear = new ArrayList(); + for (NodeRef personNodeRef : allPeople) { - nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null); - usageService.deleteDeltas(personNodeRef); + Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT); + 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); - - if (logger.isDebugEnabled()) + + // execute in READ-ONLY txn + List personRefsToClear = transactionService.getRetryingTransactionHelper().doInTransaction(getPersonRefs, true); + + 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 clearPersonUsage = new RetryingTransactionCallback() { - logger.debug("Enabled - calculate missing usages ..."); - } - - RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper(); + public Integer execute() throws Throwable + { + nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null); + 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> getAllPeople = new RetryingTransactionCallback>() { public Set execute() throws Throwable { Set allPeople = personService.getAllPeople(); + + if (logger.isDebugEnabled()) + { + logger.debug("Found " + allPeople.size() + " people"); + } + Set userNames = new HashSet(); 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); if (currentUsage == null) { @@ -248,11 +289,18 @@ public class UserUsageTrackingComponent userNames.add(userName); } } + + if (logger.isDebugEnabled()) + { + logger.debug("Found " + userNames.size() + " users to recalculate"); + } + return userNames; } }; + // execute in READ-ONLY txn - final Set userNames = txnHelper.doInTransaction(getAllPeople, true); + Set userNames = transactionService.getRetryingTransactionHelper().doInTransaction(getAllPeople, true); for (final String userName : userNames) { @@ -266,9 +314,9 @@ public class UserUsageTrackingComponent }, 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 */ - public void recalculateUsage(final String username) - { - final RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper(); - - // wrap to make the request in a transaction + private void recalculateUsage(final String username) + { RetryingTransactionCallback calculatePersonCurrentUsage = new RetryingTransactionCallback() { public Long execute() throws Throwable { -// QNameEntity ownerQnameEntity = qnameDAO.getQNameEntity(ContentModel.PROP_OWNER); -// QNameEntity contentQnameEntity = qnameDAO.getQNameEntity(ContentModel.PROP_CONTENT); -// List stores = contentUsageImpl.getStores(); final MutableLong totalUsage = new MutableLong(0L); @@ -298,11 +340,11 @@ public class UserUsageTrackingComponent { 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() { 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); - 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); - } - - NodePropertyHandler propCreatorHandler = new NodePropertyHandler() - { - public void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value) + public boolean handle(Pair nodePair) { - if (!nodeTypeQName.equals(ContentModel.TYPE_CONTENT)) - { - // It is not content - return; - } + NodeRef nodeRef = nodePair.getSecond(); + if (nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER) != null) { - // There is an owner property so we will have process this already - return; + // There is an owner property so we will have processed this already + return true; // continue to next node (more required) } + ContentData contentData = DefaultTypeConverter.INSTANCE.convert( ContentData.class, nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT)); @@ -350,42 +386,38 @@ public class UserUsageTrackingComponent long currentTotalUsage = totalUsage.longValue(); 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); - logger.debug("Recalc usage ("+ username+") totalUsage="+totalUsage+", quota="+quotaSize); + logger.trace("Recalc usage ("+ username+") totalUsage="+totalUsage+", quota="+quotaSize); } 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 updatePersonCurrentUsage = new RetryingTransactionCallback() { public Object execute() throws Throwable { NodeRef personNodeRef = personService.getPerson(username); - if (!nodeService.exists(personNodeRef)) - { - // Ignore - return null; - } contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage); usageService.deleteDeltas(personNodeRef); return null; } }; - // execute in txn - txnHelper.doInTransaction(updatePersonCurrentUsage, false); + // execute in READ-WRITE txn + transactionService.getRetryingTransactionHelper().doInTransaction(updatePersonCurrentUsage, false); } /** @@ -394,9 +426,6 @@ public class UserUsageTrackingComponent private void collapseUsages() { // Collapse usage deltas (if a person has initial usage set) - final RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper(); - - // wrap to make the request in a transaction RetryingTransactionCallback collapseUsages = new RetryingTransactionCallback() { public Object execute() throws Throwable @@ -425,9 +454,9 @@ public class UserUsageTrackingComponent usageService.deleteDeltas(personNodeRef); 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 @@ -446,7 +475,7 @@ public class UserUsageTrackingComponent } }; - // execute in txn - txnHelper.doInTransaction(collapseUsages, false); + // execute in READ-WRITE txn + transactionService.getRetryingTransactionHelper().doInTransaction(collapseUsages, false); } }