mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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
This commit is contained in:
@@ -228,13 +228,13 @@
|
||||
<ref bean="sandboxFactory" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- AVM Locking. -->
|
||||
|
||||
<bean id="avmLockingService" class="org.alfresco.repo.avm.locking.AVMLockingServiceImpl">
|
||||
<property name="attributeService">
|
||||
<ref bean="attributeService"/>
|
||||
</property>
|
||||
|
||||
<!-- AVM Locking. -->
|
||||
|
||||
<bean id="avmLockingService" class="org.alfresco.repo.avm.locking.AVMLockingServiceImpl">
|
||||
<property name="attributeService">
|
||||
<ref bean="attributeService"/>
|
||||
</property>
|
||||
<property name="authorityService">
|
||||
<ref bean="authorityService"/>
|
||||
</property>
|
||||
@@ -250,6 +250,9 @@
|
||||
<property name="webProjectStore">
|
||||
<value>workspace://SpacesStore</value>
|
||||
</property>
|
||||
<property name="avmLockDAO">
|
||||
<ref bean="avmLockDAO"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@@ -158,6 +158,11 @@
|
||||
<property name="versionRootEntityCache" ref="avmVersionRootEntityCache"/>
|
||||
</bean>
|
||||
|
||||
<bean id="avmLockDAO" class="org.alfresco.repo.domain.avm.ibatis.AVMLockDAOImpl">
|
||||
<property name="sqlMapClientTemplate" ref="avmSqlMapClientTemplate"/>
|
||||
<property name="propertyValueDAO" ref="propertyValueDAO"/>
|
||||
</bean>
|
||||
|
||||
<!-- Permissions (including ACLs / ACEs) -->
|
||||
|
||||
<bean id="permissionsDaoComponent" class="org.alfresco.repo.service.StoreRedirectorProxyFactory">
|
||||
|
@@ -218,6 +218,14 @@
|
||||
<parameter property="qnameId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
</parameterMap>
|
||||
|
||||
<parameterMap id="parameterMap_delete_PropertyUniqueContextByValues" class="map">
|
||||
<parameter property="value1PropId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="value2PropId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="value3LikeStr" jdbcType="VARCHAR" javaType="java.lang.String"/>
|
||||
<parameter property="lockDataStoreKey" jdbcType="VARCHAR" javaType="java.lang.String"/>
|
||||
<parameter property="lockDataStoreValue" jdbcType="VARCHAR" javaType="java.lang.String"/>
|
||||
</parameterMap>
|
||||
|
||||
|
||||
<!-- -->
|
||||
<!-- SQL Snippets -->
|
||||
@@ -1226,4 +1234,60 @@
|
||||
class_type = 'layeredfile'
|
||||
</select>
|
||||
|
||||
<!--
|
||||
Optimised delete of AVM locks (as used by WCM web projects)
|
||||
|
||||
note: assumes that directory path to match
|
||||
- does not start with /
|
||||
- is lower-case
|
||||
- ends with /
|
||||
for example:
|
||||
- 'www/avm_webapps/root/this/is/an/example/dirtomatch/'
|
||||
-->
|
||||
<delete id="delete_PropertyUniqueContextByValuesWithOneKV" parameterMap="parameterMap_delete_PropertyUniqueContextByValues">
|
||||
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>
|
||||
|
||||
<delete id="delete_PropertyUniqueContextByValuesWithNoKV" parameterMap="parameterMap_delete_PropertyUniqueContextByValues">
|
||||
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 ?
|
||||
)
|
||||
</delete>
|
||||
|
||||
</sqlMap>
|
@@ -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<String> pathKeys = new ArrayList<String>(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<String, String> lockData = (Map<String, String>) value;
|
||||
|
||||
for (Map.Entry<String, String> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
46
source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java
Normal file
46
source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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:
|
||||
*
|
||||
* <b>alf_prop_unique_ctx</b>
|
||||
*
|
||||
* @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<String, String> lockDataToMatch);
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<String, String> lockDataToMatch)
|
||||
{
|
||||
Long avmLocksValueId = null;
|
||||
Pair<Long, Serializable> 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);
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<String, Object> params = new HashMap<String, Object>(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<String, Object> params = new HashMap<String, Object>(3);
|
||||
params.put("value1PropId", avmLocksValueId);
|
||||
params.put("value2PropId", avmStoreNameId);
|
||||
params.put("value3LikeStr", dirPathToMatch);
|
||||
|
||||
return template.delete(DELETE_MATCHING_AVM_LOCKS_0_KV, params);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user