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 8beadc7..5b42d0e 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,6 +11,7 @@ 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; @@ -18,6 +19,8 @@ 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; @@ -48,12 +51,18 @@ public abstract class AbstractNodeActionService { @Autowired private NamespaceService namespaceService; + @Autowired + private NodeService nodeService; + @Autowired private ApiService apiService; @Autowired private ExecutorManager executorManager; + @Autowired + private SolrShardHashService shardHashService; + @Autowired(required = false) @Qualifier(Constants.QUALIFIER_ASIE) private ShardRegistry shardRegistry; @@ -216,42 +225,56 @@ public abstract class AbstractNodeActionService { List instances = new LinkedList<>(); - List slicedInstances = this.shardRegistry.getIndexSlice(searchParams); - if (slicedInstances != null) { - this.logger.trace("Due to a sharding method, considering only applicable shards and their ASIE nodes: {}: {}", nodeDbId, slicedInstances); - - for (ShardInstance instance : slicedInstances) - instances.add(this.toModel(instance)); - } else { - for (Entry>> floc : this.shardRegistry.getFlocs().entrySet()) { - if (!floc.getKey().getStoreRefs().contains(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE)) - continue; - for (Entry> shard : floc.getValue().entrySet()) { - for (ShardState shardState : shard.getValue()) + // we need a ShardRegistry method like getIndexSlice, but + // (1) works with shard methods other than explicit + // (2) returns all possible instances/nodes, not just one node per instance + + for (Entry>> floc : this.shardRegistry.getFlocs().entrySet()) { + if (!floc.getKey().getStoreRefs().contains(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE)) + continue; + + Integer shardHash = null; + ShardSet shardset = null; + for (Entry> shard : floc.getValue().entrySet()) { + for (ShardState shardState : shard.getValue()) { + // every shard and instance (state) in the FLOC is the same + // but we need one ShardState to determine the full configuration + // 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); + } + } + + if (shardHash != null) { + if (shard.getKey().getInstance() == shardHash) + instances.add(this.toModel(shardState.getShardInstance(), shardState)); + } else { instances.add(this.toModel(shardState.getShardInstance(), shardState)); + } } } - - this.logger.trace("Despite sharding, considering all shards and nodes: {}: {}", nodeDbId, instances); } + return instances; } - private com.inteligr8.alfresco.asie.model.ShardInstance toModel(ShardInstance instance) { - // get any random shardState - Floc floc = instance.getShard().getFloc(); - Map> shardsStates = this.shardRegistry.getFlocs().get(floc); - if (shardsStates == null) - throw new IllegalStateException(); - Set shardStates = shardsStates.get(instance.getShard()); - if (shardStates == null || shardStates.isEmpty()) - throw new IllegalStateException(); - ShardState anyShardState = shardStates.iterator().next(); - - return this.toModel(instance, anyShardState); - } - private com.inteligr8.alfresco.asie.model.ShardInstance toModel(ShardInstance instance, ShardState anyShardState) { Floc floc = instance.getShard().getFloc(); diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/service/AcsReconcileService.java b/shared/src/main/java/com/inteligr8/alfresco/asie/service/AcsReconcileService.java index e494a85..1f38868 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/service/AcsReconcileService.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/service/AcsReconcileService.java @@ -289,19 +289,19 @@ public class AcsReconcileService implements InitializingBean, DisposableBean { @Override public void success(ShardInstance instance) { - reconcileLogger.info("INDEXED: {} <=> {}", nodeDbId, nodeRef); + reconcileLogger.info("INDEXED: {} <=> {} in {}", nodeDbId, nodeRef, instance); syncHosts.add(instance); } @Override public void scheduled(ShardInstance instance) { - reconcileLogger.info("INDEXING: {} <=> {}", nodeDbId, nodeRef); + reconcileLogger.info("INDEXING: {} <=> {} in {}", nodeDbId, nodeRef, instance); asyncHosts.add(instance); } @Override public void error(ShardInstance instance, String message) { - reconcileLogger.info("FAILED INDEX: {} <=> {}", nodeDbId, nodeRef); + reconcileLogger.info("FAILED INDEX: {} <=> {} in {}", nodeDbId, nodeRef, instance); errorHosts.put(instance, message); } }; @@ -331,19 +331,19 @@ public class AcsReconcileService implements InitializingBean, DisposableBean { @Override public void success(ShardInstance instance) { - reconcileLogger.info("REINDEXED: {} <=> {}", nodeDbId, nodeRef); + reconcileLogger.info("REINDEXED: {} <=> {} in {}", nodeDbId, nodeRef, instance); syncHosts.add(instance); } @Override public void scheduled(ShardInstance instance) { - reconcileLogger.info("REINDEXING: {} <=> {}", nodeDbId, nodeRef); + reconcileLogger.info("REINDEXING: {} <=> {} in {}", nodeDbId, nodeRef, instance); asyncHosts.add(instance); } @Override public void error(ShardInstance instance, String message) { - reconcileLogger.info("FAILED REINDEX: {} <=> {}", nodeDbId, nodeRef); + reconcileLogger.info("FAILED REINDEX: {} <=> {} in {}", nodeDbId, nodeRef, instance); errorHosts.put(instance, message); } };