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:
Jan Vonka
2010-06-23 12:39:14 +00:00
parent f3a7a0aa7c
commit 9e403f1447
7 changed files with 323 additions and 62 deletions

View File

@@ -228,13 +228,13 @@
<ref bean="sandboxFactory" /> <ref bean="sandboxFactory" />
</property> </property>
</bean> </bean>
<!-- AVM Locking. --> <!-- AVM Locking. -->
<bean id="avmLockingService" class="org.alfresco.repo.avm.locking.AVMLockingServiceImpl"> <bean id="avmLockingService" class="org.alfresco.repo.avm.locking.AVMLockingServiceImpl">
<property name="attributeService"> <property name="attributeService">
<ref bean="attributeService"/> <ref bean="attributeService"/>
</property> </property>
<property name="authorityService"> <property name="authorityService">
<ref bean="authorityService"/> <ref bean="authorityService"/>
</property> </property>
@@ -250,6 +250,9 @@
<property name="webProjectStore"> <property name="webProjectStore">
<value>workspace://SpacesStore</value> <value>workspace://SpacesStore</value>
</property> </property>
<property name="avmLockDAO">
<ref bean="avmLockDAO"/>
</property>
</bean> </bean>
</beans> </beans>

View File

@@ -158,6 +158,11 @@
<property name="versionRootEntityCache" ref="avmVersionRootEntityCache"/> <property name="versionRootEntityCache" ref="avmVersionRootEntityCache"/>
</bean> </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) --> <!-- Permissions (including ACLs / ACEs) -->
<bean id="permissionsDaoComponent" class="org.alfresco.repo.service.StoreRedirectorProxyFactory"> <bean id="permissionsDaoComponent" class="org.alfresco.repo.service.StoreRedirectorProxyFactory">

View File

@@ -218,6 +218,14 @@
<parameter property="qnameId" jdbcType="BIGINT" javaType="java.lang.Long"/> <parameter property="qnameId" jdbcType="BIGINT" javaType="java.lang.Long"/>
</parameterMap> </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 --> <!-- SQL Snippets -->
@@ -1226,4 +1234,60 @@
class_type = 'layeredfile' class_type = 'layeredfile'
</select> </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> </sqlMap>

View File

@@ -19,19 +19,16 @@
package org.alfresco.repo.avm.locking; 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.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.model.WCMAppModel; import org.alfresco.model.WCMAppModel;
import org.alfresco.repo.domain.avm.AVMLockDAO;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.attributes.AttributeService; import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.attributes.DuplicateAttributeException; 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.AVMBadArgumentException;
import org.alfresco.service.cmr.avm.locking.AVMLockingException; import org.alfresco.service.cmr.avm.locking.AVMLockingException;
import org.alfresco.service.cmr.avm.locking.AVMLockingService; 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.AuthorityType;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.util.EqualsHelper;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.alfresco.wcm.util.WCMUtil; import org.alfresco.wcm.util.WCMUtil;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@@ -70,6 +66,8 @@ public class AVMLockingServiceImpl implements AVMLockingService
private AuthorityService authorityService; private AuthorityService authorityService;
private PersonService personService; private PersonService personService;
private NodeService nodeService; private NodeService nodeService;
private AVMLockDAO avmLockDAO;
/** /**
* @param webProjectStore The webProjectStore to set * @param webProjectStore The webProjectStore to set
@@ -102,17 +100,22 @@ public class AVMLockingServiceImpl implements AVMLockingService
{ {
this.personService = personService; this.personService = personService;
} }
public void setSearchService(SearchService searchService) public void setSearchService(SearchService searchService)
{ {
this.searchService = searchService; this.searchService = searchService;
} }
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
this.nodeService = nodeService; this.nodeService = nodeService;
} }
public void setAvmLockDAO(AVMLockDAO avmLockDAO)
{
this.avmLockDAO = avmLockDAO;
}
/** /**
* Appends the lock owner to the lock data. * Appends the lock owner to the lock data.
*/ */
@@ -317,54 +320,8 @@ public class AVMLockingServiceImpl implements AVMLockingService
dirPathStart = dirPath; dirPathStart = dirPath;
} }
final List<String> pathKeys = new ArrayList<String>(10); // optimised to delete with single DB query
avmLockDAO.removeLocks(avmStore, dirPathStart, lockDataToMatch);
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);
}
} }
/** /**

View 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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}