From 9e403f144735afb0e7f9204b45f2482ef4a00530 Mon Sep 17 00:00:00 2001 From: Jan Vonka Date: Wed, 23 Jun 2010 12:39:14 +0000 Subject: [PATCH] Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-4 to HEAD: 20682: SAIL-239 (SAIL-294) - optimise AVM removeLocks into single delete - also verified SQL syntax across MySQL, PostgreSQL, Oracle, MSSQL & DB2 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20773 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/avm-services-context.xml | 17 +-- config/alfresco/dao/dao-context.xml | 5 + .../avm-common-SqlMap.xml | 64 +++++++++++ .../avm/locking/AVMLockingServiceImpl.java | 67 ++--------- .../alfresco/repo/domain/avm/AVMLockDAO.java | 46 ++++++++ .../domain/avm/AbstractAVMLockDAOImpl.java | 108 ++++++++++++++++++ .../domain/avm/ibatis/AVMLockDAOImpl.java | 78 +++++++++++++ 7 files changed, 323 insertions(+), 62 deletions(-) create mode 100644 source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java create mode 100644 source/java/org/alfresco/repo/domain/avm/AbstractAVMLockDAOImpl.java create mode 100644 source/java/org/alfresco/repo/domain/avm/ibatis/AVMLockDAOImpl.java diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml index 7770ef2da2..abb05145dc 100644 --- a/config/alfresco/avm-services-context.xml +++ b/config/alfresco/avm-services-context.xml @@ -228,13 +228,13 @@ - - - - - - - + + + + + + + @@ -250,6 +250,9 @@ workspace://SpacesStore + + + diff --git a/config/alfresco/dao/dao-context.xml b/config/alfresco/dao/dao-context.xml index 5b0484b864..eb413b708b 100644 --- a/config/alfresco/dao/dao-context.xml +++ b/config/alfresco/dao/dao-context.xml @@ -158,6 +158,11 @@ + + + + + diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml index 0118a39050..ccc8d0382b 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml @@ -218,6 +218,14 @@ + + + + + + + + @@ -1226,4 +1234,60 @@ class_type = 'layeredfile' + + + delete from + alf_prop_unique_ctx + where exists + ( + select + * + from + alf_prop_value pv3 + join alf_prop_string_value psv3 on (psv3.id = pv3.long_value), + alf_prop_link pl + left join alf_prop_value pkey on (pkey.id = pl.key_prop_id and pkey.persisted_type = 3) + left join alf_prop_string_value psvk on (psvk.id = pkey.long_value) + left join alf_prop_value pval on (pval.id = pl.value_prop_id and pval.persisted_type = 3) + left join alf_prop_string_value psvv on (psvv.id = pval.long_value) + where + value1_prop_id = ? and + value2_prop_id = ? and + value3_prop_id = pv3.id and + pv3.persisted_type = 3 and + psv3.string_value like ? and + prop1_id = pl.root_prop_id and + psvk.string_value = ? and + psvv.string_value = ? + ) + + + + delete from + alf_prop_unique_ctx + where exists + ( + select + * + from + alf_prop_value pv3 + join alf_prop_string_value psv3 on (psv3.id = pv3.long_value) + where + value1_prop_id = ? and + value2_prop_id = ? and + value3_prop_id = pv3.id and + pv3.persisted_type = 3 and + psv3.string_value like ? + ) + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java index aedbe52c93..837cc7aa77 100644 --- a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java @@ -19,19 +19,16 @@ package org.alfresco.repo.avm.locking; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.alfresco.model.WCMAppModel; +import org.alfresco.repo.domain.avm.AVMLockDAO; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.attributes.AttributeService; import org.alfresco.service.cmr.attributes.DuplicateAttributeException; -import org.alfresco.service.cmr.attributes.AttributeService.AttributeQueryCallback; import org.alfresco.service.cmr.avm.AVMBadArgumentException; import org.alfresco.service.cmr.avm.locking.AVMLockingException; import org.alfresco.service.cmr.avm.locking.AVMLockingService; @@ -44,7 +41,6 @@ import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.util.EqualsHelper; import org.alfresco.util.ParameterCheck; import org.alfresco.wcm.util.WCMUtil; import org.apache.commons.logging.Log; @@ -70,6 +66,8 @@ public class AVMLockingServiceImpl implements AVMLockingService private AuthorityService authorityService; private PersonService personService; private NodeService nodeService; + + private AVMLockDAO avmLockDAO; /** * @param webProjectStore The webProjectStore to set @@ -102,17 +100,22 @@ public class AVMLockingServiceImpl implements AVMLockingService { this.personService = personService; } - + public void setSearchService(SearchService searchService) { this.searchService = searchService; } - + public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } + public void setAvmLockDAO(AVMLockDAO avmLockDAO) + { + this.avmLockDAO = avmLockDAO; + } + /** * Appends the lock owner to the lock data. */ @@ -317,54 +320,8 @@ public class AVMLockingServiceImpl implements AVMLockingService dirPathStart = dirPath; } - final List pathKeys = new ArrayList(10); - - AttributeQueryCallback callback = new AttributeQueryCallback() - { - @SuppressWarnings("unchecked") - public boolean handleAttribute(Long id, Serializable value, Serializable[] keys) - { - if (keys.length != 3 || !EqualsHelper.nullSafeEquals(keys[0], KEY_AVM_LOCKS) || keys[1] == null || keys[2] == null || value == null) - { - logger.warn("Unexpected AVM lock attribute: \n" + - " id: " + id + "\n" + - " keys: " + Arrays.toString(keys) + "\n" + - " value: " + value); - return true; - } - - Map lockData = (Map) value; - - for (Map.Entry entry : lockDataToMatch.entrySet()) - { - String lockDataValue = lockData.get(entry.getKey()); - if (lockDataValue != null) - { - if (! lockDataValue.equals(entry.getValue())) - { - return true; - } - } - } - - String pathKey = (String)keys[2]; - - if (dirPathStart == null || pathKey.startsWith(dirPathStart)) - { - pathKeys.add(pathKey); - } - - // Continue - return true; - } - }; - - attributeService.getAttributes(callback, KEY_AVM_LOCKS, avmStore); - - for (String pathKey : pathKeys) - { - attributeService.removeAttribute(KEY_AVM_LOCKS, avmStore, pathKey); - } + // optimised to delete with single DB query + avmLockDAO.removeLocks(avmStore, dirPathStart, lockDataToMatch); } /** diff --git a/source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java b/source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java new file mode 100644 index 0000000000..0a49346f46 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.repo.domain.avm; + +import java.util.Map; + +/** + * DAO service to remove AVM locks. + * + * Added here for now, since this is currently an WCM-specific use-case to optimise lock removal + * based on matching path (bypassing the Attribute Service -> PropVal DAO). See also AbstractPropertyValueDAOImpl. + * Affected table is currently: + * + * alf_prop_unique_ctx + * + * @author janv + * @since 3.4 + */ +public interface AVMLockDAO +{ + /** + * Remove all locks for a specific AVM store that start with a given directory path + * that also optionally match a map of lock data entries. + * + * @param avmStore the name of the AVM store + * @param dirPath optional - start with given directory path or null to match all + * @param lockDataToMatch optional - lock data to match (note: all entries must match) or null/empty to match all + */ + public void removeLocks(String avmStore, String dirPath, final Map lockDataToMatch); +} diff --git a/source/java/org/alfresco/repo/domain/avm/AbstractAVMLockDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/AbstractAVMLockDAOImpl.java new file mode 100644 index 0000000000..a71797aab7 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/avm/AbstractAVMLockDAOImpl.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.repo.domain.avm; + +import java.io.Serializable; +import java.util.Map; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.avm.locking.AVMLockingServiceImpl; +import org.alfresco.repo.domain.propval.PropertyValueDAO; +import org.alfresco.util.Pair; +import org.alfresco.wcm.util.WCMUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Abstract implementation for AVMLock DAO. + * + * @author janv + * @since 3.4 + */ +public abstract class AbstractAVMLockDAOImpl implements AVMLockDAO +{ + protected final Log logger = LogFactory.getLog(this.getClass()); + + private PropertyValueDAO propertyValueDAO; + + public void setPropertyValueDAO(PropertyValueDAO propertyValueDAO) + { + this.propertyValueDAO = propertyValueDAO; + } + + /** + * Default constructor. + */ + public AbstractAVMLockDAOImpl() + { + } + + /** + * {@inheritDoc} + */ + public void removeLocks(String avmStore, String dirPathToMatch, final Map lockDataToMatch) + { + Long avmLocksValueId = null; + Pair valuePair = propertyValueDAO.getPropertyValue(AVMLockingServiceImpl.KEY_AVM_LOCKS); + if (valuePair == null) + { + // No such value, so no need to delete + return; + } + avmLocksValueId = valuePair.getFirst(); + + Long avmStoreNameId = null; + valuePair = propertyValueDAO.getPropertyValue(avmStore); + if (valuePair == null) + { + // No such value, so no need to delete + return; + } + avmStoreNameId = valuePair.getFirst(); + + String lockDataStoreKey = null; + String lockDataStoreValue = null; + + if ((lockDataToMatch != null) && (lockDataToMatch.size() > 0)) + { + lockDataStoreKey = WCMUtil.LOCK_KEY_STORE_NAME; + + if ((lockDataToMatch.size() != 1) || (! lockDataToMatch.containsKey(lockDataStoreKey))) + { + throw new AlfrescoRuntimeException("Expected lockData to contain either no entries or only one entry with key: "+lockDataStoreKey); + } + + lockDataStoreValue = lockDataToMatch.get(lockDataStoreKey); + } + + int deleted = deletePropertyUniqueContexts(avmLocksValueId, avmStoreNameId, dirPathToMatch, lockDataStoreKey, lockDataStoreValue); + + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Deleted " + deleted + " unique property contexts: \n" + + " dirPathToMatch: " + dirPathToMatch + "\n" + + " lockDataToMatch: " + lockDataToMatch); + } + } + + protected abstract int deletePropertyUniqueContexts(Long avmLocksValueId, Long avmStoreNameId, String dirPathToMatch, String lockDataStoreKey, String lockDataStoreValue); +} diff --git a/source/java/org/alfresco/repo/domain/avm/ibatis/AVMLockDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/ibatis/AVMLockDAOImpl.java new file mode 100644 index 0000000000..f539b1f904 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/avm/ibatis/AVMLockDAOImpl.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.repo.domain.avm.ibatis; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.repo.domain.avm.AbstractAVMLockDAOImpl; +import org.springframework.orm.ibatis.SqlMapClientTemplate; + +/** + * iBatis-specific implementation of the AVMLock DAO. + * + * @author janv + * @since 3.4 + */ +public class AVMLockDAOImpl extends AbstractAVMLockDAOImpl +{ + private static final String DELETE_MATCHING_AVM_LOCKS_1_KV ="alfresco.avm.delete_PropertyUniqueContextByValuesWithOneKV"; + private static final String DELETE_MATCHING_AVM_LOCKS_0_KV ="alfresco.avm.delete_PropertyUniqueContextByValuesWithNoKV"; + + private SqlMapClientTemplate template; + + public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) + { + this.template = sqlMapClientTemplate; + } + + @Override + protected int deletePropertyUniqueContexts(Long avmLocksValueId, Long avmStoreNameId, String dirPathToMatch, String lockDataStoreKey, String lockDataStoreValue) + { + if (dirPathToMatch == null) + { + dirPathToMatch = "%"; + } + else if (! dirPathToMatch.endsWith("%")) + { + dirPathToMatch = dirPathToMatch + "%"; + } + + if (lockDataStoreKey != null) + { + Map params = new HashMap(5); + params.put("value1PropId", avmLocksValueId); + params.put("value2PropId", avmStoreNameId); + params.put("value3LikeStr", dirPathToMatch); + params.put("lockDataStoreKey", lockDataStoreKey); + params.put("lockDataStoreValue", lockDataStoreValue); + + return template.delete(DELETE_MATCHING_AVM_LOCKS_1_KV, params); + } + else + { + Map params = new HashMap(3); + params.put("value1PropId", avmLocksValueId); + params.put("value2PropId", avmStoreNameId); + params.put("value3LikeStr", dirPathToMatch); + + return template.delete(DELETE_MATCHING_AVM_LOCKS_0_KV, params); + } + } +}