MT - fix user usages for tenants

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8197 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2008-02-05 15:43:17 +00:00
parent fc136a58de
commit 998dbc59f0
8 changed files with 265 additions and 215 deletions

View File

@@ -233,7 +233,7 @@
</bean> </bean>
<bean id="userUsageCollapseComponent" class="org.alfresco.repo.usage.UserUsageTrackingComponent"> <bean id="userUsageTrackingComponent" class="org.alfresco.repo.usage.UserUsageTrackingComponent">
<property name="nodeDaoService"> <property name="nodeDaoService">
<ref bean="nodeDaoService"/> <ref bean="nodeDaoService"/>
</property> </property>
@@ -252,36 +252,15 @@
<property name="usageService"> <property name="usageService">
<ref bean="usageService"/> <ref bean="usageService"/>
</property> </property>
<property name="enabled"> <property name="tenantService">
<value>${system.usages.enabled}</value> <ref bean="tenantService" />
</property> </property>
</bean> <property name="tenantDeployerService">
<ref bean="tenantAdminService" />
<bean id="userUsageBootstrapComponent" class="org.alfresco.repo.usage.UserUsageTrackingComponent">
<property name="nodeDaoService">
<ref bean="nodeDaoService"/>
</property>
<property name="transactionService">
<ref bean="transactionService"/>
</property>
<property name="contentUsageImpl">
<ref bean="contentUsageImpl"/>
</property>
<property name="personService">
<ref bean="personService"/>
</property>
<property name="nodeService">
<ref bean="nodeService"/>
</property>
<property name="usageService">
<ref bean="usageService"/>
</property> </property>
<property name="enabled"> <property name="enabled">
<value>${system.usages.enabled}</value> <value>${system.usages.enabled}</value>
</property> </property>
<property name="bootstrap">
<value>true</value>
</property>
</bean> </bean>
<!-- enable scheduler property to activate --> <!-- enable scheduler property to activate -->
@@ -293,8 +272,8 @@
</property> </property>
<property name="jobDataAsMap"> <property name="jobDataAsMap">
<map> <map>
<entry key="userUsageCollapseComponent"> <entry key="userUsageTrackingComponent">
<ref bean="userUsageCollapseComponent" /> <ref bean="userUsageTrackingComponent" />
</entry> </entry>
</map> </map>
</property> </property>
@@ -326,8 +305,8 @@
</property> </property>
<property name="jobDataAsMap"> <property name="jobDataAsMap">
<map> <map>
<entry key="userUsageBootstrapComponent"> <entry key="userUsageTrackingComponent">
<ref bean="userUsageBootstrapComponent" /> <ref bean="userUsageTrackingComponent" />
</entry> </entry>
</map> </map>
</property> </property>

View File

@@ -5,15 +5,9 @@
<beans> <beans>
<bean id="usageService" class="org.alfresco.repo.usage.UsageServiceImpl"> <bean id="usageService" class="org.alfresco.repo.usage.UsageServiceImpl">
<property name="usageDeltaDao"> <property name="usageDeltaDao" ref="usageDeltaDao"/>
<ref bean="usageDeltaDao"/> <property name="nodeDaoService" ref="nodeDaoService"/>
</property> <property name="tenantService" ref="tenantService"/>
<property name="nodeDaoService">
<ref bean="nodeDaoService" />
</property>
<property name="tenantService">
<ref bean="tenantService"/>
</property>
</bean> </bean>
<bean id="contentUsageImpl" class="org.alfresco.repo.usage.ContentUsageImpl" init-method="init"> <bean id="contentUsageImpl" class="org.alfresco.repo.usage.ContentUsageImpl" init-method="init">
@@ -22,6 +16,7 @@
<property name="policyComponent" ref="policyComponent"/> <property name="policyComponent" ref="policyComponent"/>
<property name="usageService" ref="usageService"/> <property name="usageService" ref="usageService"/>
<property name="authenticationComponent" ref="authenticationComponent"/> <property name="authenticationComponent" ref="authenticationComponent"/>
<property name="tenantService" ref="tenantService"/>
<property name="enabled"> <property name="enabled">
<value>${system.usages.enabled}</value> <value>${system.usages.enabled}</value>
</property> </property>

View File

@@ -50,6 +50,8 @@ import org.alfresco.repo.node.db.DbNodeServiceImpl;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
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.usage.UserUsageBootstrapJob;
import org.alfresco.repo.usage.UserUsageTrackingComponent;
import org.alfresco.repo.workflow.WorkflowDeployer; import org.alfresco.repo.workflow.WorkflowDeployer;
import org.alfresco.service.cmr.admin.RepoAdminService; import org.alfresco.service.cmr.admin.RepoAdminService;
import org.alfresco.service.cmr.attributes.AttributeService; import org.alfresco.service.cmr.attributes.AttributeService;
@@ -871,6 +873,10 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
spacesImporterBootstrap.bootstrap(); spacesImporterBootstrap.bootstrap();
// calculate any missing usages
UserUsageTrackingComponent userUsageTrackingComponent = (UserUsageTrackingComponent)getApplicationContext().getBean(UserUsageBootstrapJob.KEY_COMPONENT);
userUsageTrackingComponent.bootstrapInternal();
logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef)); logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef));
} }

View File

@@ -33,6 +33,7 @@ import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -63,6 +64,7 @@ public class ContentUsageImpl implements ContentUsageService,
private PolicyComponent policyComponent; private PolicyComponent policyComponent;
private UsageService usageService; private UsageService usageService;
private AuthenticationComponent authenticationComponent; private AuthenticationComponent authenticationComponent;
private TenantService tenantService;
private boolean enabled = true; private boolean enabled = true;
@@ -93,6 +95,11 @@ public class ContentUsageImpl implements ContentUsageService,
this.authenticationComponent = authenticationComponent; this.authenticationComponent = authenticationComponent;
} }
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setEnabled(boolean enabled) public void setEnabled(boolean enabled)
{ {
this.enabled = enabled; this.enabled = enabled;
@@ -144,7 +151,7 @@ public class ContentUsageImpl implements ContentUsageService,
public void onCreateNode(ChildAssociationRef childAssocRef) public void onCreateNode(ChildAssociationRef childAssocRef)
{ {
NodeRef nodeRef = childAssocRef.getChildRef(); NodeRef nodeRef = childAssocRef.getChildRef();
if (stores.contains(nodeRef.getStoreRef().toString())) if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()))
{ {
// Get content size // Get content size
@@ -180,7 +187,7 @@ public class ContentUsageImpl implements ContentUsageService,
Map<QName, Serializable> before, Map<QName, Serializable> before,
Map<QName, Serializable> after) Map<QName, Serializable> after)
{ {
if (stores.contains(nodeRef.getStoreRef().toString())) if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()))
{ {
// Check for change in content size // Check for change in content size
@@ -273,7 +280,7 @@ public class ContentUsageImpl implements ContentUsageService,
*/ */
public void beforeDeleteNode(NodeRef nodeRef) public void beforeDeleteNode(NodeRef nodeRef)
{ {
if (stores.contains(nodeRef.getStoreRef().toString())) if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()))
{ {
// TODO use data dictionary to get content property // TODO use data dictionary to get content property
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);

View File

@@ -85,11 +85,11 @@ public class UsageServiceImpl implements UsageService
{ {
Set<Node> nodes = usageDeltaDao.getUsageDeltaNodes(); Set<Node> nodes = usageDeltaDao.getUsageDeltaNodes();
// convert nodes to nodeRefs // convert nodes to nodeRefs (tenant-specific)
Set<NodeRef> results = new HashSet<NodeRef>(nodes.size()); Set<NodeRef> results = new HashSet<NodeRef>(nodes.size());
for (Node node : nodes) for (Node node : nodes)
{ {
results.add(tenantService.getBaseName(node.getNodeRef())); results.add(node.getNodeRef());
} }
return results; return results;
} }

View File

@@ -40,7 +40,7 @@ import org.quartz.JobExecutionException;
*/ */
public class UserUsageBootstrapJob implements Job public class UserUsageBootstrapJob implements Job
{ {
private static final String KEY_COMPONENT = "userUsageBootstrapComponent"; public static final String KEY_COMPONENT = "userUsageTrackingComponent";
public void execute(JobExecutionContext context) throws JobExecutionException public void execute(JobExecutionContext context) throws JobExecutionException
{ {
@@ -50,7 +50,7 @@ public class UserUsageBootstrapJob implements Job
{ {
throw new JobExecutionException("Missing job data: " + KEY_COMPONENT); throw new JobExecutionException("Missing job data: " + KEY_COMPONENT);
} }
// perform the content usage calculations // perform the content usage bootstrap
usageComponent.execute(); usageComponent.bootstrap();
} }
} }

View File

@@ -34,7 +34,7 @@ import org.quartz.JobExecutionException;
*/ */
public class UserUsageCollapseJob implements Job public class UserUsageCollapseJob implements Job
{ {
private static final String KEY_COMPONENT = "userUsageCollapseComponent"; private static final String KEY_COMPONENT = "userUsageTrackingComponent";
public void execute(JobExecutionContext context) throws JobExecutionException public void execute(JobExecutionContext context) throws JobExecutionException
{ {

View File

@@ -33,6 +33,10 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.Node;
import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.node.db.NodeDaoService;
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.tenant.Tenant;
import org.alfresco.repo.tenant.TenantDeployerService;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.transaction.RetryingTransactionHelper; 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;
@@ -58,8 +62,6 @@ public class UserUsageTrackingComponent
private static boolean busy = false; private static boolean busy = false;
private boolean bootstrap = false;
private NodeDaoService nodeDaoService; private NodeDaoService nodeDaoService;
private TransactionServiceImpl transactionService; private TransactionServiceImpl transactionService;
private ContentUsageImpl contentUsageImpl; private ContentUsageImpl contentUsageImpl;
@@ -67,6 +69,8 @@ public class UserUsageTrackingComponent
private PersonService personService; private PersonService personService;
private NodeService nodeService; private NodeService nodeService;
private UsageService usageService; private UsageService usageService;
private TenantDeployerService tenantDeployerService;
private TenantService tenantService;
private boolean enabled = true; private boolean enabled = true;
@@ -86,11 +90,6 @@ public class UserUsageTrackingComponent
this.contentUsageImpl = contentUsageImpl; this.contentUsageImpl = contentUsageImpl;
} }
public void setBootstrap(boolean bootstrap)
{
this.bootstrap = bootstrap;
}
public void setPersonService(PersonService personService) public void setPersonService(PersonService personService)
{ {
this.personService = personService; this.personService = personService;
@@ -106,159 +105,164 @@ public class UserUsageTrackingComponent
this.usageService = usageService; this.usageService = usageService;
} }
public void setTenantDeployerService(TenantDeployerService tenantDeployerService)
{
this.tenantDeployerService = tenantDeployerService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setEnabled(boolean enabled) public void setEnabled(boolean enabled)
{ {
this.enabled = enabled; this.enabled = enabled;
} }
public void execute() public void execute()
{ {
try if (enabled == true)
{ {
if (! busy && ! enabled) if (! busy)
{ {
busy = true; try
{
busy = true;
// disabled - remove all usages // collapse usages - note: for MT environment, will collapse for all tenants
if (bootstrap == true) collapseUsages();
{ }
if (logger.isDebugEnabled()) finally
{ {
logger.debug("Disabled - clear usages for all users ..."); busy = false;
} }
}
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Integer> clearAllUsages = new RetryingTransactionCallback<Integer>()
{
public Integer execute() throws Throwable
{
Set<NodeRef> allPeople = personService.getAllPeople();
for (NodeRef personNodeRef : allPeople)
{
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null);
usageService.deleteDeltas(personNodeRef);
}
return allPeople.size();
}
};
// execute in txn
int count = txnHelper.doInTransaction(clearAllUsages, false);
if (logger.isDebugEnabled())
{
logger.debug("... cleared usages for " + count + " users");
}
}
}
else if (! busy && enabled)
{
busy = true;
if (bootstrap == true)
{
if (logger.isDebugEnabled())
{
logger.debug("Enabled - calculate missing usages ...");
}
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Set<String>> getAllPeople = new RetryingTransactionCallback<Set<String>>()
{
public Set<String> execute() throws Throwable
{
Set<NodeRef> allPeople = personService.getAllPeople();
Set<String> userNames = new HashSet<String>();
for (NodeRef personNodeRef : allPeople)
{
Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT);
if (currentUsage == null)
{
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
userNames.add(userName);
}
}
return userNames;
}
};
// execute in READ-ONLY txn
final Set<String> userNames = txnHelper.doInTransaction(getAllPeople, true);
for (String userName : userNames)
{
recalculateUsage(userName);
}
if (logger.isDebugEnabled())
{
logger.debug("... calculated missing usages for " + userNames.size() + " users");
}
}
else
{
// Collapse usage deltas (if a person has initial usage set)
final RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction and run as System user
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
return txnHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
// Get distinct candidates
Set<NodeRef> usageNodeRefs = usageService.getUsageDeltaNodes();
for(NodeRef usageNodeRef : usageNodeRefs)
{
QName nodeType = nodeService.getType(usageNodeRef);
if (nodeType.equals(ContentModel.TYPE_PERSON))
{
NodeRef personNodeRef = usageNodeRef;
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef);
if (currentUsage != -1)
{
// collapse the usage deltas
currentUsage = contentUsageImpl.getUserUsage(userName);
usageService.deleteDeltas(personNodeRef);
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
if (logger.isDebugEnabled())
{
logger.debug("Collapsed usage: username=" + userName + ", usage=" + currentUsage);
}
}
else
{
if (logger.isWarnEnabled())
{
logger.warn("Initial usage for user has not yet been calculated: " + userName);
}
}
}
}
return null;
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
}
} }
finally }
// called once on startup
public void bootstrap()
{
// default domain
bootstrapInternal();
if (tenantService.isEnabled())
{
List<Tenant> tenants = tenantDeployerService.getAllTenants();
for (Tenant tenant : tenants)
{
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
bootstrapInternal();
return null;
}
}, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenant.getTenantDomain()));
}
}
}
public void bootstrapInternal()
{
if (! busy)
{
try
{
busy = true;
if (enabled)
{
// enabled - calculate missing usages
calculateMissingUsages();
}
else
{
// disabled - remove all usages
clearAllUsages();
}
}
finally
{
busy = false;
}
}
}
public void clearAllUsages()
{
if (logger.isDebugEnabled())
{ {
busy = false; logger.debug("Disabled - clear usages for all users ...");
}
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Integer> clearAllUsages = new RetryingTransactionCallback<Integer>()
{
public Integer execute() throws Throwable
{
Set<NodeRef> allPeople = personService.getAllPeople();
for (NodeRef personNodeRef : allPeople)
{
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null);
usageService.deleteDeltas(personNodeRef);
}
return allPeople.size();
}
};
// execute in txn
int count = txnHelper.doInTransaction(clearAllUsages, false);
if (logger.isDebugEnabled())
{
logger.debug("... cleared usages for " + count + " users");
}
}
public void calculateMissingUsages()
{
if (logger.isDebugEnabled())
{
logger.debug("Enabled - calculate missing usages ...");
}
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Set<String>> getAllPeople = new RetryingTransactionCallback<Set<String>>()
{
public Set<String> execute() throws Throwable
{
Set<NodeRef> allPeople = personService.getAllPeople();
Set<String> userNames = new HashSet<String>();
for (NodeRef personNodeRef : allPeople)
{
Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT);
if (currentUsage == null)
{
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
userNames.add(userName);
}
}
return userNames;
}
};
// execute in READ-ONLY txn
final Set<String> userNames = txnHelper.doInTransaction(getAllPeople, true);
for (String userName : userNames)
{
recalculateUsage(userName);
}
if (logger.isDebugEnabled())
{
logger.debug("... calculated missing usages for " + userNames.size() + " users");
} }
} }
@@ -323,22 +327,81 @@ public class UserUsageTrackingComponent
// execute in READ-ONLY txn // execute in READ-ONLY txn
final Long currentUsage = txnHelper.doInTransaction(calculatePersonCurrentUsage, true); final Long currentUsage = txnHelper.doInTransaction(calculatePersonCurrentUsage, true);
// wrap to make the request in a transaction and run as System user // wrap to make the request in a transaction
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() RetryingTransactionCallback<Object> updatePersonCurrentUsage = new RetryingTransactionCallback<Object>()
{ {
public Object doWork() throws Exception public Object execute() throws Throwable
{ {
return txnHelper.doInTransaction(new RetryingTransactionCallback<Object>() NodeRef personNodeRef = personService.getPerson(userName);
{ contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
public Object execute() throws Throwable usageService.deleteDeltas(personNodeRef);
{ return null;
NodeRef personNodeRef = personService.getPerson(userName);
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
usageService.deleteDeltas(personNodeRef);
return null;
}
});
} }
}, AuthenticationUtil.getSystemUserName()); };
// execute in txn
txnHelper.doInTransaction(updatePersonCurrentUsage, false);
}
/**
* Collapse usages - note: for MT environment, will collapse all tenants
*/
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<Object> collapseUsages = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
// Get distinct candidates
Set<NodeRef> usageNodeRefs = usageService.getUsageDeltaNodes();
for(final NodeRef usageNodeRef : usageNodeRefs)
{
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
QName nodeType = nodeService.getType(usageNodeRef);
if (nodeType.equals(ContentModel.TYPE_PERSON))
{
NodeRef personNodeRef = usageNodeRef;
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef);
if (currentUsage != -1)
{
// collapse the usage deltas
currentUsage = contentUsageImpl.getUserUsage(userName);
usageService.deleteDeltas(personNodeRef);
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
if (logger.isDebugEnabled())
{
logger.debug("Collapsed usage: username=" + userName + ", usage=" + currentUsage);
}
}
else
{
if (logger.isWarnEnabled())
{
logger.warn("Initial usage for user has not yet been calculated: " + userName);
}
}
}
return null;
}
}, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantService.getDomain(usageNodeRef.getStoreRef().getIdentifier())));
}
return null;
}
};
// execute in txn
txnHelper.doInTransaction(collapseUsages, false);
} }
} }