[ACS-10041] Repository - CPU spikes and OOM errors with SQL Server 2019 (#3588)

This commit is contained in:
cezary-witkowski
2025-09-23 14:10:29 +02:00
committed by GitHub
parent 1251081a69
commit ef034e596b
5 changed files with 6538 additions and 6437 deletions

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2025 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -23,105 +23,102 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.domain.node;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
/**
* Class holding properties associated with the <b>sys:referenceable</b> aspect.
* This aspect is common enough to warrant direct inclusion on the <b>Node</b> entity.
*
* @author Derek Hulley
* @since 3.4
*/
public class ReferenceablePropertiesEntity
{
private static final Set<QName> REFERENCEABLE_PROP_QNAMES;
static
{
REFERENCEABLE_PROP_QNAMES = new HashSet<QName>(8);
REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_STORE_PROTOCOL);
REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_STORE_IDENTIFIER);
REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_NODE_UUID);
REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_NODE_DBID);
}
/**
* @return Returns <tt>true</tt> if the property belongs to the <b>sys:referenceable</b> aspect
*/
public static boolean isReferenceableProperty(QName qname)
{
return REFERENCEABLE_PROP_QNAMES.contains(qname);
}
/**
* Remove all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties
*/
public static void removeReferenceableProperties(Node node, Map<QName, Serializable> properties)
{
properties.keySet().removeAll(REFERENCEABLE_PROP_QNAMES);
String name = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_NAME));
if (name != null && name.equals(node.getUuid()))
{
// The cm:name matches the UUID, so drop it
properties.remove(ContentModel.PROP_NAME);
}
}
/**
* Remove all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties
*/
public static void removeReferenceableProperties(Set<QName> propertyQNames)
{
propertyQNames.removeAll(REFERENCEABLE_PROP_QNAMES);
}
/**
* Adds all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties.
*/
public static void addReferenceableProperties(Node node, Map<QName, Serializable> properties)
{
Long nodeId = node.getId();
NodeRef nodeRef = node.getNodeRef();
properties.put(ContentModel.PROP_STORE_PROTOCOL, nodeRef.getStoreRef().getProtocol());
properties.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier());
properties.put(ContentModel.PROP_NODE_UUID, nodeRef.getId());
properties.put(ContentModel.PROP_NODE_DBID, nodeId);
// add the ID as the name, if required
String name = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_NAME));
if (name == null)
{
properties.put(ContentModel.PROP_NAME, nodeRef.getId());
}
}
public static Serializable getReferenceableProperty(Node node, QName qname)
{
NodeRef nodeRef = node.getNodeRef();
if (qname.equals(ContentModel.PROP_STORE_PROTOCOL))
{
return nodeRef.getStoreRef().getProtocol();
}
else if (qname.equals(ContentModel.PROP_STORE_IDENTIFIER))
{
return nodeRef.getStoreRef().getIdentifier();
}
else if (qname.equals(ContentModel.PROP_NODE_UUID))
{
return nodeRef.getId();
}
else if (qname.equals(ContentModel.PROP_NODE_DBID))
{
return node.getId();
}
throw new IllegalArgumentException("Not sys:referenceable property: " + qname);
}
}
package org.alfresco.repo.domain.node;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
/**
* Class holding properties associated with the <b>sys:referenceable</b> aspect. This aspect is common enough to warrant direct inclusion on the <b>Node</b> entity.
*
* @author Derek Hulley
* @since 3.4
*/
public class ReferenceablePropertiesEntity
{
private static final Set<QName> REFERENCEABLE_PROP_QNAMES;
static
{
REFERENCEABLE_PROP_QNAMES = new HashSet<QName>(8);
REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_STORE_PROTOCOL);
REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_STORE_IDENTIFIER);
REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_NODE_UUID);
REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_NODE_DBID);
}
/**
* @return Returns <tt>true</tt> if the property belongs to the <b>sys:referenceable</b> aspect
*/
public static boolean isReferenceableProperty(QName qname)
{
return REFERENCEABLE_PROP_QNAMES.contains(qname);
}
/**
* Remove all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties
*/
public static void removeReferenceableProperties(Node node, Map<QName, Serializable> properties)
{
properties.keySet().removeAll(REFERENCEABLE_PROP_QNAMES);
String name = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_NAME));
if (name != null && name.equals(node.getUuid()))
{
// The cm:name matches the UUID, so drop it
properties.remove(ContentModel.PROP_NAME);
}
}
/**
* Remove all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties
*/
public static void removeReferenceableProperties(Set<QName> propertyQNames)
{
propertyQNames.removeAll(REFERENCEABLE_PROP_QNAMES);
}
/**
* Adds all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties.
*/
public static void addReferenceableProperties(Long nodeId, NodeRef nodeRef, Map<QName, Serializable> properties)
{
properties.put(ContentModel.PROP_STORE_PROTOCOL, nodeRef.getStoreRef().getProtocol());
properties.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier());
properties.put(ContentModel.PROP_NODE_UUID, nodeRef.getId());
properties.put(ContentModel.PROP_NODE_DBID, nodeId);
// add the ID as the name, if required
String name = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_NAME));
if (name == null)
{
properties.put(ContentModel.PROP_NAME, nodeRef.getId());
}
}
public static Serializable getReferenceableProperty(Node node, QName qname)
{
NodeRef nodeRef = node.getNodeRef();
if (qname.equals(ContentModel.PROP_STORE_PROTOCOL))
{
return nodeRef.getStoreRef().getProtocol();
}
else if (qname.equals(ContentModel.PROP_STORE_IDENTIFIER))
{
return nodeRef.getStoreRef().getIdentifier();
}
else if (qname.equals(ContentModel.PROP_NODE_UUID))
{
return nodeRef.getId();
}
else if (qname.equals(ContentModel.PROP_NODE_DBID))
{
return node.getId();
}
throw new IllegalArgumentException("Not sys:referenceable property: " + qname);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2025 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -23,239 +23,290 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.node.getchildren;
import java.util.List;
import java.util.Set;
import org.alfresco.repo.domain.node.NodeEntity;
import org.alfresco.repo.domain.node.NodePropertyEntity;
/**
* Filterable/Sortable Node Entity
*
* Can be optionally filtered/sorted by (up to) three properties - note: sort properties are applied in order
*
* @author jan
* @since 4.0
*/
public class FilterSortNodeEntity
{
private Long id; // node id
private NodeEntity node;
private NodePropertyEntity prop1;
private NodePropertyEntity prop2;
private NodePropertyEntity prop3;
// Supplemental query-related parameters
private Long parentNodeId;
private Long prop1qnameId;
private Long prop2qnameId;
private Long prop3qnameId;
private List<Long> childNodeTypeQNameIds;
private Set<Long> assocTypeQNameIds;
private String pattern;
private Long namePropertyQNameId;
private boolean auditableProps;
private boolean nodeType;
private Boolean isPrimary;
/**
* Default constructor
*/
public FilterSortNodeEntity()
{
auditableProps = false;
}
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getPattern()
{
return pattern;
}
protected String escape(String s, char escapeChar)
{
StringBuilder sb = new StringBuilder();
int idx = -1;
int offset = 0;
do
{
idx = s.indexOf(escapeChar, offset);
if(idx != -1)
{
sb.append(s.substring(offset, idx));
sb.append("\\");
sb.append(escapeChar);
offset = idx + 1;
}
}
while(idx != -1);
sb.append(s.substring(offset));
return sb.toString();
}
public void setPattern(String pattern)
{
if(pattern != null)
{
// escape the '%' character with '\' (standard SQL escape character)
pattern = escape(pattern, '%');
// replace the wildcard character '*' with the one used in database queries i.e. '%'
this.pattern = pattern.replace('*', '%');
}
}
public void setAssocTypeQNameIds(Set<Long> assocTypeQNameIds)
{
this.assocTypeQNameIds = assocTypeQNameIds;
}
public Set<Long> getAssocTypeQNameIds()
{
return assocTypeQNameIds;
}
public Long getNamePropertyQNameId()
{
return namePropertyQNameId;
}
public void setNamePropertyQNameId(Long namePropertyQNameId)
{
this.namePropertyQNameId = namePropertyQNameId;
}
public NodePropertyEntity getProp1()
{
return prop1;
}
public void setProp1(NodePropertyEntity prop1)
{
this.prop1 = prop1;
}
public NodePropertyEntity getProp2()
{
return prop2;
}
public void setProp2(NodePropertyEntity prop2)
{
this.prop2 = prop2;
}
public NodePropertyEntity getProp3()
{
return prop3;
}
public void setProp3(NodePropertyEntity prop3)
{
this.prop3 = prop3;
}
public NodeEntity getNode()
{
return node;
}
public void setNode(NodeEntity childNode)
{
this.node = childNode;
}
// Supplemental query-related parameters
public Long getParentNodeId()
{
return parentNodeId;
}
public void setParentNodeId(Long parentNodeId)
{
this.parentNodeId = parentNodeId;
}
public Long getProp1qnameId()
{
return prop1qnameId;
}
public void setProp1qnameId(Long prop1qnameId)
{
this.prop1qnameId = prop1qnameId;
}
public Long getProp2qnameId()
{
return prop2qnameId;
}
public void setProp2qnameId(Long prop2qnameId)
{
this.prop2qnameId = prop2qnameId;
}
public Long getProp3qnameId()
{
return prop3qnameId;
}
public void setProp3qnameId(Long prop3qnameId)
{
this.prop3qnameId = prop3qnameId;
}
public List<Long> getChildNodeTypeQNameIds()
{
return childNodeTypeQNameIds;
}
public void setChildNodeTypeQNameIds(List<Long> childNodeTypeQNameIds)
{
this.childNodeTypeQNameIds = childNodeTypeQNameIds;
}
public boolean isAuditableProps()
{
return auditableProps;
}
public void setAuditableProps(boolean auditableProps)
{
this.auditableProps = auditableProps;
}
public boolean isNodeType()
{
return nodeType;
}
public void setNodeType(boolean nodeType)
{
this.nodeType = nodeType;
}
public Boolean isPrimary()
{
return isPrimary;
}
public void setIsPrimary(Boolean isPrimary)
{
this.isPrimary = isPrimary;
}
}
package org.alfresco.repo.node.getchildren;
import java.util.List;
import java.util.Set;
import org.alfresco.repo.domain.node.AuditablePropertiesEntity;
import org.alfresco.repo.domain.node.NodePropertyEntity;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
/**
* Filterable/Sortable Node Entity
*
* Can be optionally filtered/sorted by (up to) three properties - note: sort properties are applied in order
*
* @author jan
* @since 4.0
*/
public class FilterSortNodeEntity
{
private Long id; // node id
private String nodeUuid;
private Long typeQNameId;
private AuditablePropertiesEntity auditablePropertiesEntity;
private NodePropertyEntity prop1;
private NodePropertyEntity prop2;
private NodePropertyEntity prop3;
private String storeProtocol;
private String storeIdentifier;
// Supplemental query-related parameters
private Long parentNodeId;
private Long prop1qnameId;
private Long prop2qnameId;
private Long prop3qnameId;
private List<Long> childNodeTypeQNameIds;
private Set<Long> assocTypeQNameIds;
private String pattern;
private Long namePropertyQNameId;
private boolean auditableProps;
private boolean nodeType;
private Boolean isPrimary;
/**
* Default constructor
*/
public FilterSortNodeEntity()
{
auditableProps = false;
}
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getNodeUuid()
{
return nodeUuid;
}
public void setNodeUuid(String nodeUuid)
{
this.nodeUuid = nodeUuid;
}
public Long getTypeQNameId()
{
return typeQNameId;
}
public void setTypeQNameId(Long typeQNameId)
{
this.typeQNameId = typeQNameId;
}
public String getPattern()
{
return pattern;
}
protected String escape(String s, char escapeChar)
{
StringBuilder sb = new StringBuilder();
int idx = -1;
int offset = 0;
do
{
idx = s.indexOf(escapeChar, offset);
if (idx != -1)
{
sb.append(s.substring(offset, idx));
sb.append("\\");
sb.append(escapeChar);
offset = idx + 1;
}
} while (idx != -1);
sb.append(s.substring(offset));
return sb.toString();
}
public void setPattern(String pattern)
{
if (pattern != null)
{
// escape the '%' character with '\' (standard SQL escape character)
pattern = escape(pattern, '%');
// replace the wildcard character '*' with the one used in database queries i.e. '%'
this.pattern = pattern.replace('*', '%');
}
}
public void setAssocTypeQNameIds(Set<Long> assocTypeQNameIds)
{
this.assocTypeQNameIds = assocTypeQNameIds;
}
public Set<Long> getAssocTypeQNameIds()
{
return assocTypeQNameIds;
}
public Long getNamePropertyQNameId()
{
return namePropertyQNameId;
}
public void setNamePropertyQNameId(Long namePropertyQNameId)
{
this.namePropertyQNameId = namePropertyQNameId;
}
public AuditablePropertiesEntity getAuditablePropertiesEntity()
{
return auditablePropertiesEntity;
}
public void setAuditablePropertiesEntity(AuditablePropertiesEntity auditablePropertiesEntity)
{
this.auditablePropertiesEntity = auditablePropertiesEntity;
}
public NodePropertyEntity getProp1()
{
return prop1;
}
public void setProp1(NodePropertyEntity prop1)
{
this.prop1 = prop1;
}
public NodePropertyEntity getProp2()
{
return prop2;
}
public void setProp2(NodePropertyEntity prop2)
{
this.prop2 = prop2;
}
public NodePropertyEntity getProp3()
{
return prop3;
}
public void setProp3(NodePropertyEntity prop3)
{
this.prop3 = prop3;
}
public String getStoreProtocol()
{
return storeProtocol;
}
public void setStoreProtocol(String storeProtocol)
{
this.storeProtocol = storeProtocol;
}
public String getStoreIdentifier()
{
return storeIdentifier;
}
public void setStoreIdentifier(String storeIdentifier)
{
this.storeIdentifier = storeIdentifier;
}
// Supplemental query-related parameters
public Long getParentNodeId()
{
return parentNodeId;
}
public void setParentNodeId(Long parentNodeId)
{
this.parentNodeId = parentNodeId;
}
public Long getProp1qnameId()
{
return prop1qnameId;
}
public void setProp1qnameId(Long prop1qnameId)
{
this.prop1qnameId = prop1qnameId;
}
public Long getProp2qnameId()
{
return prop2qnameId;
}
public void setProp2qnameId(Long prop2qnameId)
{
this.prop2qnameId = prop2qnameId;
}
public Long getProp3qnameId()
{
return prop3qnameId;
}
public void setProp3qnameId(Long prop3qnameId)
{
this.prop3qnameId = prop3qnameId;
}
public List<Long> getChildNodeTypeQNameIds()
{
return childNodeTypeQNameIds;
}
public void setChildNodeTypeQNameIds(List<Long> childNodeTypeQNameIds)
{
this.childNodeTypeQNameIds = childNodeTypeQNameIds;
}
public boolean isAuditableProps()
{
return auditableProps;
}
public void setAuditableProps(boolean auditableProps)
{
this.auditableProps = auditableProps;
}
public boolean isNodeType()
{
return nodeType;
}
public void setNodeType(boolean nodeType)
{
this.nodeType = nodeType;
}
public Boolean isPrimary()
{
return isPrimary;
}
public void setIsPrimary(Boolean isPrimary)
{
this.isPrimary = isPrimary;
}
public NodeRef createNodeRef()
{
return new NodeRef(new StoreRef(storeProtocol, storeIdentifier), nodeUuid);
}
}

View File

@@ -133,7 +133,15 @@
<resultMap id="result_FilterSortNode" type="FilterSortNode">
<id property="id" column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="nodeUuid" column="uuid" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="typeQNameId" column="type_qname_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="auditablePropertiesEntity.auditCreator" column="audit_creator" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="auditablePropertiesEntity.auditCreated" column="audit_created" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="auditablePropertiesEntity.auditModifier" column="audit_modifier" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="auditablePropertiesEntity.auditModified" column="audit_modified" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="auditablePropertiesEntity.auditAccessed" column="audit_accessed" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="prop1.nodeId" column="prop1_node_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="prop1.key.qnameId" column="prop1_qname_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="prop1.key.localeId" column="prop1_locale_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
@@ -169,8 +177,9 @@
<result property="prop3.value.floatValue" column="prop3_float_value" jdbcType="FLOAT" javaType="java.lang.Float"/>
<result property="prop3.value.doubleValue" column="prop3_double_value" jdbcType="FLOAT" javaType="java.lang.Double"/>
<result property="prop3.value.stringValue" column="prop3_string_value" jdbcType="VARCHAR" javaType="java.lang.String"/>
<association property="node" resultMap="alfresco.node.result_Node"/>
<result property="storeProtocol" column="protocol" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="storeIdentifier" column="identifier" jdbcType="VARCHAR" javaType="java.lang.String"/>
</resultMap>
@@ -972,8 +981,8 @@
</select>
<!-- GetChildren - with explicit prop filtering and/or sorting -->
<select id="select_GetChildrenCannedQueryWithProps" parameterType="FilterSortNode" resultMap="result_FilterSortNode">
select
<select id="select_GetChildrenCannedQueryWithProps" parameterType="FilterSortNode" resultMap="result_FilterSortNode" flushCache="true">
select distinct
childNode.id as id,
childNode.version as version,
childStore.id as store_id,
@@ -989,7 +998,7 @@
childNode.audit_created as audit_created,
childNode.audit_modifier as audit_modifier,
childNode.audit_modified as audit_modified,
childNode.audit_accessed as audit_accessed
childNode.audit_accessed as audit_accessed
<if test="prop1qnameId != null">
, prop1.node_id as prop1_node_id,
prop1.qname_id as prop1_qname_id,
@@ -1067,9 +1076,6 @@
#{item}
</foreach>
</if>
<if test="prop1qnameId == null and auditableProps == false">
<include refid="alfresco.node.select_ChildAssoc_OrderBy"/>
</if>
</select>
<!-- GetChildren - with no explicit sorting (or prop filtering) - note: still filtered by child type (and optionally primary or secondary) -->