diff --git a/config/alfresco/usage-services-context.xml b/config/alfresco/usage-services-context.xml index 0a49f83089..0f4f1940b5 100644 --- a/config/alfresco/usage-services-context.xml +++ b/config/alfresco/usage-services-context.xml @@ -52,7 +52,6 @@ - @@ -61,6 +60,7 @@ + diff --git a/source/java/org/alfresco/repo/usage/RepoUsageComponent.java b/source/java/org/alfresco/repo/usage/RepoUsageComponent.java index 98af5b6d92..d7de1d0185 100644 --- a/source/java/org/alfresco/repo/usage/RepoUsageComponent.java +++ b/source/java/org/alfresco/repo/usage/RepoUsageComponent.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.usage; import org.alfresco.service.cmr.admin.RepoUsage; @@ -39,11 +39,6 @@ import org.alfresco.service.namespace.QName; */ public interface RepoUsageComponent { - public static final Long LOCK_TTL = 60000L; - public static final QName LOCK_USAGE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "RepoUsageComponent"); - public static final QName LOCK_USAGE_USERS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "RepoUsageComponent.Users"); - public static final QName LOCK_USAGE_DOCUMENTS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "RepoUsageComponent.Documents"); - public static final String KEY_USAGE_ROOT = ".repoUsages"; public static final String KEY_USAGE_CURRENT = "current"; public static final String KEY_USAGE_LAST_UPDATE_USERS = "lastUpdateUsers"; diff --git a/source/java/org/alfresco/repo/usage/RepoUsageComponentImpl.java b/source/java/org/alfresco/repo/usage/RepoUsageComponentImpl.java index f61befd6a3..8f5acfeec0 100644 --- a/source/java/org/alfresco/repo/usage/RepoUsageComponentImpl.java +++ b/source/java/org/alfresco/repo/usage/RepoUsageComponentImpl.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.usage; import java.util.ArrayList; @@ -39,8 +39,6 @@ import org.alfresco.ibatis.IdsEntity; import org.alfresco.model.ContentModel; import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.domain.query.CannedQueryDAO; -import org.alfresco.repo.lock.JobLockService; -import org.alfresco.repo.lock.LockAcquisitionException; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; import org.alfresco.service.cmr.admin.RepoUsage; @@ -52,7 +50,7 @@ import org.alfresco.service.cmr.attributes.AttributeService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; +import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.DateUtil; import org.alfresco.util.PropertyCheck; import org.apache.commons.logging.Log; @@ -77,7 +75,6 @@ public class RepoUsageComponentImpl implements RepoUsageComponent private AuthorityService authorityService; private AttributeService attributeService; private DictionaryService dictionaryService; - private JobLockService jobLockService; private CannedQueryDAO cannedQueryDAO; private QNameDAO qnameDAO; @@ -130,14 +127,6 @@ public class RepoUsageComponentImpl implements RepoUsageComponent this.dictionaryService = dictionaryService; } - /** - * @param jobLockService service to prevent duplicate work when updating usages - */ - public void setJobLockService(JobLockService jobLockService) - { - this.jobLockService = jobLockService; - } - /** * @param cannedQueryDAO DAO for executing queries */ @@ -169,7 +158,6 @@ public class RepoUsageComponentImpl implements RepoUsageComponent PropertyCheck.mandatory(this, "authorityService", authorityService); PropertyCheck.mandatory(this, "attributeService", attributeService); PropertyCheck.mandatory(this, "dictionaryService", dictionaryService); - PropertyCheck.mandatory(this, "jobLockService", jobLockService); PropertyCheck.mandatory(this, "cannedQueryDAO", cannedQueryDAO); PropertyCheck.mandatory(this, "qnameDAO", qnameDAO); } @@ -287,48 +275,28 @@ public class RepoUsageComponentImpl implements RepoUsageComponent */ private boolean updateUsers(boolean reset) { - String lockToken = null; - try - { - // Lock to prevent concurrent queries - lockToken = jobLockService.getLock(LOCK_USAGE_USERS, LOCK_TTL); - Long userCount = 0L; - - if (!reset) - { - // Count users - IdsEntity idsParam = new IdsEntity(); - idsParam.setIdOne(qnameDAO.getOrCreateQName(ContentModel.ASPECT_PERSON_DISABLED).getFirst()); - idsParam.setIdTwo(qnameDAO.getOrCreateQName(ContentModel.TYPE_PERSON).getFirst()); - userCount = cannedQueryDAO.executeCountQuery(QUERY_NS, QUERY_SELECT_COUNT_PERSONS_NOT_DISABLED, idsParam); - - // We subtract one to cater for 'guest', which is implicit - userCount = userCount > 0L ? userCount - 1L : 0L; + Long userCount = 0L; - // Lock again to be sure we still have the right to update - jobLockService.refreshLock(lockToken, LOCK_USAGE_USERS, LOCK_TTL); - } - attributeService.setAttribute( - new Long(System.currentTimeMillis()), - KEY_USAGE_ROOT, KEY_USAGE_CURRENT, KEY_USAGE_LAST_UPDATE_USERS); - attributeService.setAttribute( - userCount, - KEY_USAGE_ROOT, KEY_USAGE_CURRENT, KEY_USAGE_USERS); - // Success - return true; - } - catch (LockAcquisitionException e) + if (!reset) { - logger.debug("Failed to get lock for user counts: " + e.getMessage()); - return false; - } - finally - { - if (lockToken != null) - { - jobLockService.releaseLock(lockToken, LOCK_USAGE_USERS); - } + // Count users + IdsEntity idsParam = new IdsEntity(); + idsParam.setIdOne(qnameDAO.getOrCreateQName(ContentModel.ASPECT_PERSON_DISABLED).getFirst()); + idsParam.setIdTwo(qnameDAO.getOrCreateQName(ContentModel.TYPE_PERSON).getFirst()); + userCount = cannedQueryDAO.executeCountQuery(QUERY_NS, QUERY_SELECT_COUNT_PERSONS_NOT_DISABLED, idsParam); + + // We subtract one to cater for 'guest', which is implicit + userCount = userCount > 0L ? userCount - 1L : 0L; + } + attributeService.setAttribute( + new Long(System.currentTimeMillis()), + KEY_USAGE_ROOT, KEY_USAGE_CURRENT, KEY_USAGE_LAST_UPDATE_USERS); + attributeService.setAttribute( + userCount, + KEY_USAGE_ROOT, KEY_USAGE_CURRENT, KEY_USAGE_USERS); + // Success + return true; } /** @@ -336,52 +304,31 @@ public class RepoUsageComponentImpl implements RepoUsageComponent */ private boolean updateDocuments(boolean reset) { - String lockToken = null; - try - { - // Lock to prevent concurrent queries - lockToken = jobLockService.getLock(LOCK_USAGE_DOCUMENTS, LOCK_TTL); - Long documentCount = 0L; + Long documentCount = 0L; - if (!reset) - { - // Count documents - Set searchTypeQNames = new HashSet(11); - Collection qnames = dictionaryService.getSubTypes(ContentModel.TYPE_CONTENT, true); - searchTypeQNames.addAll(qnames); - searchTypeQNames.add(ContentModel.TYPE_CONTENT); - qnames = dictionaryService.getSubTypes(ContentModel.TYPE_LINK, true); - searchTypeQNames.addAll(qnames); - searchTypeQNames.add(ContentModel.TYPE_LINK); - Set searchTypeQNameIds = qnameDAO.convertQNamesToIds(searchTypeQNames, false); - IdsEntity idsParam = new IdsEntity(); - idsParam.setIds(new ArrayList(searchTypeQNameIds)); - documentCount = cannedQueryDAO.executeCountQuery(QUERY_NS, QUERY_SELECT_COUNT_DOCUMENTS, idsParam); - - // Lock again to be sure we still have the right to update - jobLockService.refreshLock(lockToken, LOCK_USAGE_DOCUMENTS, LOCK_TTL); - } - attributeService.setAttribute( - new Long(System.currentTimeMillis()), - KEY_USAGE_ROOT, KEY_USAGE_CURRENT, KEY_USAGE_LAST_UPDATE_DOCUMENTS); - attributeService.setAttribute( - documentCount, - KEY_USAGE_ROOT, KEY_USAGE_CURRENT, KEY_USAGE_DOCUMENTS); - // Success - return true; - } - catch (LockAcquisitionException e) + if (!reset) { - logger.debug("Failed to get lock for document counts: " + e.getMessage()); - return false; - } - finally - { - if (lockToken != null) - { - jobLockService.releaseLock(lockToken, LOCK_USAGE_DOCUMENTS); - } + // Count documents + Set searchTypeQNames = new HashSet(11); + Collection qnames = dictionaryService.getSubTypes(ContentModel.TYPE_CONTENT, true); + searchTypeQNames.addAll(qnames); + searchTypeQNames.add(ContentModel.TYPE_CONTENT); + qnames = dictionaryService.getSubTypes(ContentModel.TYPE_LINK, true); + searchTypeQNames.addAll(qnames); + searchTypeQNames.add(ContentModel.TYPE_LINK); + Set searchTypeQNameIds = qnameDAO.convertQNamesToIds(searchTypeQNames, false); + IdsEntity idsParam = new IdsEntity(); + idsParam.setIds(new ArrayList(searchTypeQNameIds)); + documentCount = cannedQueryDAO.executeCountQuery(QUERY_NS, QUERY_SELECT_COUNT_DOCUMENTS, idsParam); } + attributeService.setAttribute( + new Long(System.currentTimeMillis()), + KEY_USAGE_ROOT, KEY_USAGE_CURRENT, KEY_USAGE_LAST_UPDATE_DOCUMENTS); + attributeService.setAttribute( + documentCount, + KEY_USAGE_ROOT, KEY_USAGE_CURRENT, KEY_USAGE_DOCUMENTS); + // Success + return true; } /** diff --git a/source/java/org/alfresco/repo/usage/RepoUsageMonitor.java b/source/java/org/alfresco/repo/usage/RepoUsageMonitor.java index 09e690a428..6f9531db00 100644 --- a/source/java/org/alfresco/repo/usage/RepoUsageMonitor.java +++ b/source/java/org/alfresco/repo/usage/RepoUsageMonitor.java @@ -1,33 +1,35 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.usage; import java.util.Date; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.lock.JobLockService; +import org.alfresco.repo.lock.LockAcquisitionException; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; @@ -62,10 +64,14 @@ import org.quartz.TriggerUtils; public class RepoUsageMonitor implements RepoUsageComponent.RestrictionObserver { private static Log logger = LogFactory.getLog(RepoUsageMonitor.class); - + + public static final Long LOCK_TTL = 60000L; + public static final QName LOCK_USAGE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "RepoUsageMonitor"); + private Scheduler scheduler; private TransactionServiceImpl transactionService; private RepoUsageComponent repoUsageComponent; + private JobLockService jobLockService; private final QName vetoName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "RepoUsageMonitor"); /** @@ -99,6 +105,14 @@ public class RepoUsageMonitor implements RepoUsageComponent.RestrictionObserver this.repoUsageComponent = repoUsageComponent; } + /** + * @param jobLockService service to prevent duplicate work when updating usages + */ + public void setJobLockService(JobLockService jobLockService) + { + this.jobLockService = jobLockService; + } + /** * Check that all properties are properly set */ @@ -107,7 +121,8 @@ public class RepoUsageMonitor implements RepoUsageComponent.RestrictionObserver PropertyCheck.mandatory(this, "scheduler", scheduler); PropertyCheck.mandatory(this, "transactionService", transactionService); PropertyCheck.mandatory(this, "repoUsageComponent", repoUsageComponent); - + PropertyCheck.mandatory(this, "jobLockService", jobLockService); + // Trigger the scheduled updates final JobDetail jobDetail = new JobDetail("rmj", Scheduler.DEFAULT_GROUP, RepoUsageMonitorJob.class); jobDetail.getJobDataMap().put("RepoUsageMonitor", this); @@ -167,7 +182,34 @@ public class RepoUsageMonitor implements RepoUsageComponent.RestrictionObserver return null; } }; - AuthenticationUtil.runAs(runAs, AuthenticationUtil.getSystemUserName()); + String lockToken = null; + TrackerJobLockRefreshCallback callback = new TrackerJobLockRefreshCallback(); + try + { + // Lock to prevent concurrent queries + lockToken = jobLockService.getLock(LOCK_USAGE, LOCK_TTL); + jobLockService.refreshLock(lockToken, LOCK_USAGE, LOCK_TTL / 2, callback); + AuthenticationUtil.runAs(runAs, AuthenticationUtil.getSystemUserName()); + } + catch (LockAcquisitionException e) + { + logger.debug("Failed to get lock for usage monitor: " + e.getMessage()); + } + finally + { + if (lockToken != null) + { + try + { + callback.isActive = false; + jobLockService.releaseLock(lockToken, LOCK_USAGE); + } + catch (LockAcquisitionException e) + { + logger.debug("Failed to release lock for usage monitor: " + e.getMessage()); + } + } + } } /** @@ -209,4 +251,24 @@ public class RepoUsageMonitor implements RepoUsageComponent.RestrictionObserver repoUsageMonitor.checkUsages(); } } + + private class TrackerJobLockRefreshCallback implements JobLockService.JobLockRefreshCallback + { + public boolean isActive = true; + + @Override + public boolean isActive() + { + return isActive; + } + + @Override + public void lockReleased() + { + if (logger.isTraceEnabled()) + { + logger.trace("lock released"); + } + } + } } diff --git a/source/test-java/org/alfresco/repo/usage/RepoUsageComponentTest.java b/source/test-java/org/alfresco/repo/usage/RepoUsageComponentTest.java index 2638fa5335..fd41d62b71 100644 --- a/source/test-java/org/alfresco/repo/usage/RepoUsageComponentTest.java +++ b/source/test-java/org/alfresco/repo/usage/RepoUsageComponentTest.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.usage; import javax.transaction.UserTransaction; @@ -236,7 +236,10 @@ public class RepoUsageComponentTest extends TestCase /** * Check that concurrent updates are prevented + * + * The test is disabled as the Component is not using JobLocks any more */ +/* public void test6ConcurrentUpdates() throws Exception { // Firstly check that we can get an update @@ -286,4 +289,5 @@ public class RepoUsageComponentTest extends TestCase jobLockService.releaseLock(lockToken, RepoUsageComponent.LOCK_USAGE_USERS); } } +*/ }