From fbf6c17206c8400353d33c6de21f60d458434d66 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Mon, 12 Jan 2026 15:29:03 -0500 Subject: [PATCH] moving shard determination to SolrShardHashService --- .../service/AbstractNodeActionService.java | 28 +------- .../asie/service/SolrShardHashService.java | 66 +++++++++++++++++++ 2 files changed, 69 insertions(+), 25 deletions(-) diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/service/AbstractNodeActionService.java b/shared/src/main/java/com/inteligr8/alfresco/asie/service/AbstractNodeActionService.java index 5b42d0e..5cfed17 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/service/AbstractNodeActionService.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/service/AbstractNodeActionService.java @@ -11,7 +11,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.regex.Matcher; import org.alfresco.model.ContentModel; import org.alfresco.repo.index.shard.Floc; @@ -19,8 +18,6 @@ import org.alfresco.repo.index.shard.Shard; import org.alfresco.repo.index.shard.ShardInstance; import org.alfresco.repo.index.shard.ShardRegistry; import org.alfresco.repo.index.shard.ShardState; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; @@ -51,9 +48,6 @@ public abstract class AbstractNodeActionService { @Autowired private NamespaceService namespaceService; - @Autowired - private NodeService nodeService; - @Autowired private ApiService apiService; @@ -233,7 +227,7 @@ public abstract class AbstractNodeActionService { if (!floc.getKey().getStoreRefs().contains(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE)) continue; - Integer shardHash = null; + int shardHash = -1; ShardSet shardset = null; for (Entry> shard : floc.getValue().entrySet()) { for (ShardState shardState : shard.getValue()) { @@ -242,26 +236,10 @@ public abstract class AbstractNodeActionService { // so we are computing the shardHash once and caching it if (shardset == null) { shardset = ShardSet.from(floc.getKey(), shardState); - switch (shardset.getMethod()) { - case PROPERTY: - this.logger.trace("Using property-based sharding method; discovering target shard ..."); - NodeRef nodeRef = this.nodeService.getNodeRef(nodeDbId); - Object propValue = this.nodeService.getProperty(nodeRef, QName.createQName(shardset.getPrefixedProperty(), this.namespaceService)); - if (propValue != null) { - this.logger.trace("Discovered node property for sharding: {} <=> {} => {}", nodeDbId, nodeRef, propValue); - Matcher matcher = shardset.getRegex().matcher(propValue.toString()); - String hashable = matcher.group(1); - this.logger.trace("Extracted shardable value from node: {} <=> {} => {}", nodeDbId, propValue, hashable); - shardHash = this.shardHashService.hash(hashable, shardset.getShards().intValue()); - this.logger.debug("Hash shardable value to shard instance ID: {} <=> {} => {}", nodeDbId, hashable, shardHash); - } - break; - default: - this.logger.trace("Despite sharding, considering all shards and nodes without optimization: {}: {}", nodeDbId, instances); - } + shardHash = this.shardHashService.computeShardInstanceId(shardset, nodeDbId); } - if (shardHash != null) { + if (shardHash >= 0) { if (shard.getKey().getInstance() == shardHash) instances.add(this.toModel(shardState.getShardInstance(), shardState)); } else { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/service/SolrShardHashService.java b/shared/src/main/java/com/inteligr8/alfresco/asie/service/SolrShardHashService.java index cda8353..a423257 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/service/SolrShardHashService.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/service/SolrShardHashService.java @@ -1,14 +1,32 @@ package com.inteligr8.alfresco.asie.service; import java.nio.charset.Charset; +import java.util.regex.Matcher; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.apache.commons.codec.digest.MurmurHash3; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.inteligr8.alfresco.asie.model.ShardSet; + @Component public class SolrShardHashService { private final Charset charset = Charset.forName("utf-8"); + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private NamespaceService namespaceService; + + @Autowired + private NodeService nodeService; public int hash(Object obj, int shardCount) { String str = obj.toString(); @@ -23,5 +41,53 @@ public class SolrShardHashService { hash.add(bytes, 0, bytes.length); return Math.abs(hash.end()) % shardCount; } + + /** + * @param shardset A ShardSet. + * @param nodeDbId The numeric database ID of an ACS node. + * @return A shard instance from 0 to 1 less than the number of shards; -1 if unable to hash. + */ + public int computeShardInstanceId(ShardSet shardset, long nodeDbId) { + NodeRef nodeRef = this.nodeService.getNodeRef(nodeDbId); + if (nodeRef == null) + throw new AlfrescoRuntimeException("The node " + nodeDbId + " does not exist"); + return this.computeShardInstanceId(shardset, nodeRef); + } + + /** + * @param shardset A ShardSet. + * @param nodeRef A reference to an ACS node. + * @return A shard instance from 0 to 1 less than the number of shards; -1 if unable to hash. + */ + public int computeShardInstanceId(ShardSet shardset, NodeRef nodeRef) { + switch (shardset.getMethod()) { + case PROPERTY: + QName hashableProperty = QName.createQName(shardset.getPrefixedProperty(), this.namespaceService); + Object fullPropertyValue = this.nodeService.getProperty(nodeRef, hashableProperty); + if (fullPropertyValue == null) { + this.logger.debug("Unable to determine shard instance ID because property does not exist on node: {}: {}", nodeRef, hashableProperty); + return -1; + } + + this.logger.trace("Discovered node property for sharding: {} => {}", nodeRef, fullPropertyValue); + String hashableValue = fullPropertyValue.toString(); + if (shardset.getRegex() != null) { + Matcher matcher = shardset.getRegex().matcher(hashableValue); + if (!matcher.find()) { + this.logger.debug("Unable to determine shard instance ID because regex pattern doesn't match the hashing property value: {}: {}: {}", nodeRef, shardset.getRegex(), hashableValue); + return -1; + } + hashableValue = matcher.group(1); + this.logger.trace("Extracted shardable value from node: {}: {} => {}", nodeRef, fullPropertyValue, hashableValue); + } + + int shardHash = this.hash(hashableValue, shardset.getShards().intValue()); + this.logger.debug("Hash shardable value to shard instance ID: {}: {} => {}", nodeRef, hashableValue, shardHash); + return shardHash; + default: + this.logger.trace("Unable to determine shard instance ID due to shard method: {}", shardset.getMethod()); + return -1; + } + } }