From 8be29fc37dbbe5146421579203c9a194f3016447 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Wed, 13 Nov 2024 18:02:19 -0500 Subject: [PATCH] substantial refactoring --- asie-api/pom.xml | 2 +- enterprise-module/pom.xml | 2 +- .../rest/AbstractUnregisterNodeWebScript.java | 12 +- .../rest/UnloadNodeShardWebScript.java | 4 +- .../enterprise/rest/UnloadNodeWebScript.java | 2 +- .../service/ShardDiscoveryService.java | 404 ++++++++++++++++++ .../enterprise/service/ShardStateService.java | 5 +- pom.xml | 2 +- shared/pom.xml | 2 +- .../inteligr8/alfresco/asie/Constants.java | 9 +- .../inteligr8/alfresco/asie/SimpleCaster.java | 48 +++ .../inteligr8/alfresco/asie/model/Node.java | 56 --- .../asie/model/RequestParameterSet.java | 5 - .../inteligr8/alfresco/asie/model/Shard.java | 68 +++ .../alfresco/asie/model/ShardInstance.java | 64 +++ .../asie/model/ShardInstanceState.java | 102 +++++ .../alfresco/asie/model/ShardSet.java | 328 +++++++++++--- .../alfresco/asie/model/SolrHost.java | 92 ++++ .../asie/rest/AbstractAsieNodeWebScript.java | 19 +- .../asie/rest/AbstractAsieShardWebScript.java | 25 +- .../rest/AbstractAsieShardableWebScript.java | 4 +- .../asie/rest/GetBackupNodeWebScript.java | 24 +- .../asie/rest/GetLeadNodeWebScript.java | 20 +- .../alfresco/asie/rest/GetNodeWebScript.java | 53 ++- .../alfresco/asie/rest/GetNodesWebScript.java | 41 +- .../rest/GetPropertyHashShardsWebScript.java | 64 +-- .../alfresco/asie/rest/GetShardWebScript.java | 48 +-- .../asie/rest/GetShardsWebScript.java | 43 +- .../alfresco/asie/rest/model/NodeInfo.java | 10 +- .../{ => rest}/model/NodeParameterSet.java | 2 +- .../asie/rest/model/NodeShardInfo.java | 11 +- .../model/NodeShardParameterSet.java | 4 +- .../rest/model/PropertyHashShardSetInfo.java | 50 +-- .../asie/rest/model/RequestParameterSet.java | 5 + .../asie/rest/model/ResponseInfo.java | 5 + .../alfresco/asie/rest/model/ShardInfo.java | 27 +- .../asie/rest/model/ShardNodeInfo.java | 21 +- .../{ => rest}/model/ShardParameterSet.java | 4 +- .../asie/rest/model/ShardSetInfo.java | 87 +++- .../asie/service/ShardBackupService.java | 37 +- .../asie/service/ShardDiscoveryService.java | 159 ------- .../alfresco/asie/spi/ShardBackupService.java | 11 +- .../asie/spi/ShardDiscoveryService.java | 126 ++++-- .../alfresco/asie/spi/ShardRegistry.java | 9 + .../alfresco/asie/spi/ShardStateService.java | 11 +- .../alfresco/asie/nodeShard.delete.desc.xml | 10 +- .../alfresco/asie/nodeShard.get.desc.xml | 41 ++ .../alfresco/asie/nodeShard.post.desc.xml | 2 +- .../alfresco/asie/shard.get.desc.xml | 10 +- solr-api/pom.xml | 2 +- 50 files changed, 1550 insertions(+), 642 deletions(-) create mode 100644 enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/service/ShardDiscoveryService.java create mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/SimpleCaster.java delete mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/model/Node.java delete mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/model/RequestParameterSet.java create mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/model/Shard.java create mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardInstance.java create mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardInstanceState.java create mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/model/SolrHost.java rename shared/src/main/java/com/inteligr8/alfresco/asie/{ => rest}/model/NodeParameterSet.java (92%) rename shared/src/main/java/com/inteligr8/alfresco/asie/{ => rest}/model/NodeShardParameterSet.java (80%) create mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/RequestParameterSet.java create mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ResponseInfo.java rename shared/src/main/java/com/inteligr8/alfresco/asie/{ => rest}/model/ShardParameterSet.java (74%) delete mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/service/ShardDiscoveryService.java create mode 100644 shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardRegistry.java create mode 100644 shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.get.desc.xml diff --git a/asie-api/pom.xml b/asie-api/pom.xml index 16e8ef2..d44825d 100644 --- a/asie-api/pom.xml +++ b/asie-api/pom.xml @@ -6,7 +6,7 @@ com.inteligr8.alfresco asie-platform-module-parent - 1.1-SNAPSHOT + 1.2-SNAPSHOT ../ diff --git a/enterprise-module/pom.xml b/enterprise-module/pom.xml index dab60a0..c072d81 100644 --- a/enterprise-module/pom.xml +++ b/enterprise-module/pom.xml @@ -6,7 +6,7 @@ com.inteligr8.alfresco asie-platform-module-parent - 1.1-SNAPSHOT + 1.2-SNAPSHOT ../ diff --git a/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/rest/AbstractUnregisterNodeWebScript.java b/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/rest/AbstractUnregisterNodeWebScript.java index 3e34e5c..0b22feb 100755 --- a/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/rest/AbstractUnregisterNodeWebScript.java +++ b/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/rest/AbstractUnregisterNodeWebScript.java @@ -9,6 +9,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import org.alfresco.repo.index.shard.Shard; import org.alfresco.repo.index.shard.ShardState; import org.alfresco.service.cmr.attributes.AttributeService; import org.alfresco.service.cmr.attributes.AttributeService.AttributeQueryCallback; @@ -23,10 +24,11 @@ import org.springframework.http.HttpStatus; import com.inteligr8.alfresco.asie.Constants; import com.inteligr8.alfresco.asie.api.CoreAdminApi; -import com.inteligr8.alfresco.asie.model.NodeParameterSet; +import com.inteligr8.alfresco.asie.model.ShardSet; import com.inteligr8.alfresco.asie.rest.AbstractAsieNodeWebScript; -import com.inteligr8.alfresco.asie.service.ShardBackupService; -import com.inteligr8.alfresco.asie.spi.ShardStateService; +import com.inteligr8.alfresco.asie.rest.model.NodeParameterSet; +import com.inteligr8.alfresco.asie.spi.ShardBackupService; +import com.inteligr8.alfresco.asie.enterprise.service.ShardStateService; import com.inteligr8.solr.model.CoreMetadata; import com.inteligr8.solr.model.core.StatusRequest; import com.inteligr8.solr.model.core.StatusResponse; @@ -99,7 +101,9 @@ public abstract class AbstractUnregisterNodeWebScript { @@ -20,7 +20,7 @@ public class UnloadNodeShardWebScript extends AbstractUnregisterNodeWebScript { diff --git a/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/service/ShardDiscoveryService.java b/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/service/ShardDiscoveryService.java new file mode 100644 index 0000000..92bf678 --- /dev/null +++ b/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/service/ShardDiscoveryService.java @@ -0,0 +1,404 @@ +package com.inteligr8.alfresco.asie.enterprise.service; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.alfresco.repo.index.shard.Floc; +import org.alfresco.repo.index.shard.Shard; +import org.alfresco.repo.index.shard.ShardInstance; +import org.alfresco.repo.index.shard.ShardMethodEnum; +import org.alfresco.repo.index.shard.ShardRegistry; +import org.alfresco.repo.index.shard.ShardState; +import org.alfresco.util.Pair; +import org.alfresco.util.collections.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.inteligr8.alfresco.asie.Constants; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; + +@Component +public class ShardDiscoveryService implements com.inteligr8.alfresco.asie.spi.ShardDiscoveryService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + @Qualifier(Constants.QUALIFIER_ASIE) + private ShardRegistry shardRegistry; + + @Override + public ShardSet findSetByCore(String core) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return null; + this.logger.trace("Found {} shard sets", flocs.size()); + + for (Entry>> floc : flocs.entrySet()) { + for (Entry> flocShard : floc.getValue().entrySet()) { + for (ShardState shardState : flocShard.getValue()) { + ShardSet shardSet = ShardSet.from(floc.getKey(), shardState); + if (shardSet.getCore().equals(core)) + return shardSet; + } + } + } + + return null; + } + + @Override + public SolrHost findNode(String nodeHostname, int nodePort) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return null; + this.logger.trace("Found {} shard sets", flocs.size()); + + Map resolvedAddresses = new HashMap<>(); + + for (Entry>> floc : flocs.entrySet()) { + for (Entry> flocShard : floc.getValue().entrySet()) { + for (ShardState shardState : flocShard.getValue()) { + ShardInstance shardInstance = shardState.getShardInstance(); + if (!nodeHostname.equalsIgnoreCase(shardInstance.getHostName())) { + if (!resolvedAddresses.containsKey(nodeHostname)) + resolvedAddresses.put(nodeHostname, this.resolve(nodeHostname)); + InetAddress nodeAddress = resolvedAddresses.get(nodeHostname); + this.logger.trace("Resolved: {} => {}", nodeHostname, nodeAddress); + if (nodeAddress == null) + continue; + + if (!resolvedAddresses.containsKey(shardInstance.getHostName())) + resolvedAddresses.put(shardInstance.getHostName(), this.resolve(shardInstance.getHostName())); + InetAddress shardInstanceAddress = resolvedAddresses.get(shardInstance.getHostName()); + this.logger.trace("Resolved: {} => {}", shardInstance.getHostName(), shardInstanceAddress); + if (!nodeAddress.equals(shardInstanceAddress)) + continue; + } + + if (nodePort == shardInstance.getPort()) { + SolrHost node = SolrHost.from(shardInstance); + this.logger.debug("Found node: {}", node); + return node; + } + } + } + } + + return null; + } + + @Override + public Map> findByNode(SolrHost node) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return Collections.emptyMap(); + this.logger.trace("Found {} shard sets", flocs.size()); + + Map> setShardStates = new HashMap<>(); + + for (Entry>> floc : flocs.entrySet()) + setShardStates.putAll(this.findByNode(node, floc.getKey(), floc.getValue())); + + return setShardStates; + } + + private Map> findByNode(SolrHost node, Floc floc, Map> shards) { + ShardSet shardSet = null; + Map> setShardStates = new HashMap<>(); + int shardStateCount = 0; + + for (Entry> flocShard : shards.entrySet()) { + for (ShardState shardState : flocShard.getValue()) { + if (shardSet == null) + shardSet = ShardSet.from(floc, shardState); + + ShardInstance shardInstance = shardState.getShardInstance(); + if (node.equals(SolrHost.from(shardInstance))) { + Map shardStates = setShardStates.get(shardSet); + if (shardStates == null) + setShardStates.put(shardSet, shardStates = new HashMap<>()); + shardStates.put(flocShard.getKey().getInstance(), ShardInstanceState.from(shardState)); + shardStateCount++; + } + } + } + + this.logger.debug("Found {} shard states for node: {}", shardStateCount, node); + return setShardStates; + } + + @Override + public Set findSetsByShardMethod(ShardMethodEnum... shardMethods) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return Collections.emptySet(); + this.logger.trace("Found {} shard sets", flocs.size()); + + Set shardMethodSet = CollectionUtils.asSet(shardMethods); + Set shardSets = new HashSet<>(); + + for (Entry>> floc : flocs.entrySet()) { + if (shardMethodSet.contains(floc.getKey().getShardMethod())) { + ShardState shardState = this.extractAnyShardState(floc.getValue()); + shardSets.add(ShardSet.from(floc.getKey(), shardState)); + } + } + + this.logger.debug("Found {} shard sets of methods: {}", flocs.size(), shardMethods); + return shardSets; + } + + @Override + public Set findNodes(ShardSet shardSet) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return Collections.emptySet(); + this.logger.trace("Found {} shard sets", flocs.size()); + + for (Entry>> floc : flocs.entrySet()) { + Set nodes = this.findNodes(shardSet, null, floc.getKey(), floc.getValue()); + if (nodes != null) { + this.logger.debug("Found {} nodes for set: {}", nodes.size(), shardSet); + return nodes; + } + } + + this.logger.debug("Found {} nodes for set: {}", 0, shardSet); + return Collections.emptySet(); + } + + @Override + public Set findNodesByShard(ShardSet shardSet, int shardId) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return Collections.emptySet(); + this.logger.trace("Found {} shard sets", flocs.size()); + + for (Entry>> floc : flocs.entrySet()) { + Set nodes = this.findNodes(shardSet, shardId, floc.getKey(), floc.getValue()); + if (nodes != null) { + this.logger.debug("Found {} nodes for shard #{} in set: {}", nodes.size(), shardId, shardSet); + return nodes; + } + } + + this.logger.debug("Found {} nodes for shard #{} in set: {}", 0, shardId, shardSet); + return Collections.emptySet(); + } + + private Set findNodes(ShardSet shardSet, Integer shardId, Floc floc, Map> shards) { + Set nodes = new HashSet<>(); + boolean checked = false; + + for (Entry> shard : shards.entrySet()) { + if (shardId == null || shardId.intValue() == shard.getKey().getInstance()) { + for (ShardState shardState : shard.getValue()) { + if (!checked && !shardSet.equals(ShardSet.from(floc, shardState))) + return null; + checked = true; + + ShardInstance shardInstance = shardState.getShardInstance(); + SolrHost node = SolrHost.from(shardInstance); + nodes.add(node); + } + } + } + + return nodes; + } + + @Override + public Map> findLatestNodeStates(ShardSet shardSet) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return Collections.emptyMap(); + this.logger.trace("Found {} shard sets", flocs.size()); + + for (Entry>> floc : flocs.entrySet()) { + Map> shardNodeStates = this.findLatestNodeStates(shardSet, floc.getKey(), floc.getValue()); + if (shardNodeStates != null) { + this.logger.debug("Found {} shard node states for set: {}", shardNodeStates.size(), shardSet); + return shardNodeStates; + } + } + + this.logger.debug("Found {} shard node states for set: {}", 0, shardSet); + return Collections.emptyMap(); + } + + private Map> findLatestNodeStates(ShardSet shardSet, Floc floc, Map> shards) { + Map> shardNodeStates = new HashMap<>(); + boolean checked = false; + + com.inteligr8.alfresco.asie.spi.ShardDiscoveryService.ShardedNodeShardStateComparator comparator = new com.inteligr8.alfresco.asie.spi.ShardDiscoveryService.ShardedNodeShardStateComparator(); + + for (Entry> shard : shards.entrySet()) { + int shardId = shard.getKey().getInstance(); + for (ShardState shardState : shard.getValue()) { + if (!checked && !shardSet.equals(ShardSet.from(floc, shardState))) + return null; + checked = true; + + ShardInstance shardInstance = shardState.getShardInstance(); + SolrHost node = SolrHost.from(shardInstance); + ShardInstanceState nodeShardState = ShardInstanceState.from(shardState); + + Pair pair = new Pair<>(node, nodeShardState); + if (comparator.compare(pair, shardNodeStates.get(shardId)) < 0) + shardNodeStates.put(shardId, pair); + } + } + + return shardNodeStates; + } + + @Override + public List> findNodeStatesByShard(ShardSet shardSet, int shardId) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return Collections.emptyList(); + this.logger.trace("Found {} shard sets", flocs.size()); + + for (Entry>> floc : flocs.entrySet()) { + List> nodeStates = this.findNodeStates(shardSet, shardId, floc.getKey(), floc.getValue()); + if (nodeStates != null) { + this.logger.debug("Found {} node states for shard #{} in set: {}", nodeStates.size(), shardId, shardSet); + return nodeStates; + } + } + + this.logger.debug("Found {} node states for shard #{} in set: {}", 0, shardId, shardSet); + return Collections.emptyList(); + } + + private List> findNodeStates(ShardSet shardSet, Integer shardId, Floc floc, Map> shards) { + List> nodeStates = new LinkedList<>(); + boolean checked = false; + + for (Entry> shard : shards.entrySet()) { + if (shardId == null || shardId.intValue() == shard.getKey().getInstance()) { + for (ShardState shardState : shard.getValue()) { + if (!checked && !shardSet.equals(ShardSet.from(floc, shardState))) + return null; + checked = true; + + ShardInstance shardInstance = shardState.getShardInstance(); + SolrHost node = SolrHost.from(shardInstance); + ShardInstanceState nodeShardState = ShardInstanceState.from(shardState); + nodeStates.add(new Pair<>(node, nodeShardState)); + } + } + } + + return nodeStates; + } + + @Override + public Set findIdsByNode(ShardSet shardSet, SolrHost node) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return Collections.emptySet(); + this.logger.trace("Found {} shard sets", flocs.size()); + + for (Entry>> floc : flocs.entrySet()) { + Set shardIds = this.findIdsByNode(shardSet, node, floc.getKey(), floc.getValue()); + if (shardIds != null) { + this.logger.debug("Found {} shards for node '{}' in set: {}", shardIds.size(), node, shardSet); + return shardIds; + } + } + + this.logger.debug("Found {} node states for node '{}' in set: {}", 0, node, shardSet); + return Collections.emptySet(); + } + + private Set findIdsByNode(ShardSet shardSet, SolrHost node, Floc floc, Map> shards) { + Set shardIds = new HashSet<>(); + boolean checked = false; + + for (Entry> shard : shards.entrySet()) { + for (ShardState shardState : shard.getValue()) { + if (!checked && !shardSet.equals(ShardSet.from(floc, shardState))) + return null; + checked = true; + + ShardInstance shardInstance = shardState.getShardInstance(); + if (node.equals(SolrHost.from(shardInstance))) + shardIds.add(shard.getKey().getInstance()); + } + } + + return shardIds; + } + + @Override + public Map findStatesByNode(ShardSet shardSet, SolrHost node) { + Map>> flocs = this.shardRegistry.getFlocs(); + if (flocs.isEmpty()) + return Collections.emptyMap(); + this.logger.trace("Found {} shard sets", flocs.size()); + + for (Entry>> floc : flocs.entrySet()) { + Map shardStates = this.findStatesByNode(shardSet, node, floc.getKey(), floc.getValue()); + if (shardStates != null) { + this.logger.debug("Found {} shard states for node '{}' in set: {}", shardStates.size(), node, shardSet); + return shardStates; + } + } + + this.logger.debug("Found {} shard states for node '{}' in set: {}", 0, node, shardSet); + return Collections.emptyMap(); + } + + private Map findStatesByNode(ShardSet shardSet, SolrHost node, Floc floc, Map> shards) { + Map shardStates = new HashMap<>(); + boolean checked = false; + + for (Entry> shard : shards.entrySet()) { + for (ShardState shardState : shard.getValue()) { + if (!checked && !shardSet.equals(ShardSet.from(floc, shardState))) + return null; + checked = true; + + ShardInstance shardInstance = shardState.getShardInstance(); + if (node.equals(SolrHost.from(shardInstance))) + shardStates.put(shard.getKey().getInstance(), ShardInstanceState.from(shardState)); + } + } + + return shardStates; + } + + private ShardState extractAnyShardState(Map> shards) { + if (shards.isEmpty()) + return null; + + for (Set shardStates : shards.values()) + for (ShardState shardState : shardStates) + return shardState; + + return null; + } + + private InetAddress resolve(String hostname) { + try { + return InetAddress.getByName(hostname); + } catch (UnknownHostException uhe) { + return null; + } + } + +} diff --git a/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/service/ShardStateService.java b/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/service/ShardStateService.java index f60fc39..c6bf625 100644 --- a/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/service/ShardStateService.java +++ b/enterprise-module/src/main/java/com/inteligr8/alfresco/asie/enterprise/service/ShardStateService.java @@ -34,7 +34,8 @@ public class ShardStateService implements com.inteligr8.alfresco.asie.spi.ShardS @Autowired @Qualifier(Constants.BEAN_SHARD_GUID_CACHE) private SimpleCache shardToGuidCache; - + + @Override public void clear() { this.logger.info("Removing all nodes/shards from the shard registry"); @@ -76,7 +77,7 @@ public class ShardStateService implements com.inteligr8.alfresco.asie.spi.ShardS this.shardToGuidCache.remove(shardState.getShardInstance()); } } - + public void iterate(AttributeQueryCallback callback) { this.attrService.getAttributes(callback, EnterpriseConstants.ATTR_SHARD_STATE); } diff --git a/pom.xml b/pom.xml index 0fb6d55..9d183c6 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.inteligr8.alfresco asie-platform-module-parent - 1.1-SNAPSHOT + 1.2-SNAPSHOT pom ASIE Platform Module Parent diff --git a/shared/pom.xml b/shared/pom.xml index 872cceb..e0e48dc 100644 --- a/shared/pom.xml +++ b/shared/pom.xml @@ -6,7 +6,7 @@ com.inteligr8.alfresco asie-platform-module-parent - 1.1-SNAPSHOT + 1.2-SNAPSHOT ../ diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/Constants.java b/shared/src/main/java/com/inteligr8/alfresco/asie/Constants.java index 08c5636..f2e5a89 100755 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/Constants.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/Constants.java @@ -6,20 +6,15 @@ public interface Constants { static final String QUALIFIER_ASIE = "asie"; - // OOTB + // defined OOTB static final String BEAN_SHARD_STATE_CACHE = "shardStateCache"; static final String BEAN_SHARD_GUID_CACHE = "shardToGuidCache"; - static final String BEAN_OFFILINE_SHARD_STATE_CACHE = "offlineShardStateCache"; - static final String BEAN_CORE_EXPLICIT_CACHE = "coreExplicitIdCache"; + static final String BEAN_SHARD_REGISTRY = "asie.ShardRegistry"; static final String BEAN_OBJECT_MAPPER = "asie.ObjectMapper"; static final String BEAN_ATTRIBUTE_SERVICE = "asie.AttributeService"; - static final String BEAN_SHARD_REGISTRY = "asie.ShardRegistry"; static final String ATTR_ASIE = "inteligr8.asie"; - static final String ATTR_ASIE_NODE_SHARD = "inteligr8.asie.nodeShard"; - static final String ATTR_STATE = "state"; - static final String ATTR_ONLINE = "online"; static final String ATTR_UNLOADED = "unloadedNode.cores"; } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/SimpleCaster.java b/shared/src/main/java/com/inteligr8/alfresco/asie/SimpleCaster.java new file mode 100644 index 0000000..092e0ce --- /dev/null +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/SimpleCaster.java @@ -0,0 +1,48 @@ +package com.inteligr8.alfresco.asie; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; + +public class SimpleCaster { + + public static T transform(String str, Class returnType) { + if (str == null) + return null; + + if (returnType.isAssignableFrom(String.class)) { + @SuppressWarnings("unchecked") + T t = (T) str; + return t; + } + + try { + Constructor constructor = returnType.getConstructor(String.class); + return constructor.newInstance(str); + } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) { + // suppress + } + + for (String staticMethod : Arrays.asList("from", "valueOf")) { + try { + return invoke(returnType, staticMethod, str); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + // suppress + } + } + + throw new IllegalArgumentException(); + } + + private static T invoke(Class returnType, String staticMethodName, Object... arguments) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method method = returnType.getDeclaredMethod(staticMethodName, String.class); + if (!returnType.isAssignableFrom(method.getReturnType())) + throw new NoSuchMethodException(); + + @SuppressWarnings("unchecked") + T t = (T) method.invoke(null, arguments); + return t; + } + +} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/Node.java b/shared/src/main/java/com/inteligr8/alfresco/asie/model/Node.java deleted file mode 100644 index 92613b7..0000000 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/model/Node.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.inteligr8.alfresco.asie.model; - -import java.io.Serializable; - -import org.alfresco.repo.index.shard.ShardInstance; - -public class Node implements Serializable { - - private static final long serialVersionUID = -8834744746109388928L; - - private final String id; - private final ShardInstance shardNode; - - public Node(ShardInstance shardNode) { - this.shardNode = shardNode; - this.id = this.getHostname() + ":" + this.getPort() + this.getPath(); - } - - public String getId() { - return this.id; - } - - public String getHostname() { - return this.shardNode.getHostName(); - } - - public int getPort() { - return this.shardNode.getPort(); - } - - public String getPath() { - // baseUrl is to the shard; we want to the node, so exclude the core - int lastSlash = this.shardNode.getBaseUrl().lastIndexOf('/'); - return this.shardNode.getBaseUrl().substring(0, lastSlash); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Node)) - return false; - - Node node = (Node) obj; - return this.id.equals(node.id); - } - - @Override - public int hashCode() { - return this.id.hashCode(); - } - - @Override - public String toString() { - return this.id; - } - -} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/RequestParameterSet.java b/shared/src/main/java/com/inteligr8/alfresco/asie/model/RequestParameterSet.java deleted file mode 100644 index 4c96557..0000000 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/model/RequestParameterSet.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.inteligr8.alfresco.asie.model; - -public interface RequestParameterSet { - -} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/Shard.java b/shared/src/main/java/com/inteligr8/alfresco/asie/model/Shard.java new file mode 100644 index 0000000..6841050 --- /dev/null +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/model/Shard.java @@ -0,0 +1,68 @@ +package com.inteligr8.alfresco.asie.model; + +import java.io.Serializable; + +import org.alfresco.repo.index.shard.Floc; + +public class Shard implements Serializable { + + private static final long serialVersionUID = 5683743181748541736L; + + public static Shard from(ShardSet shardSet, int shardId) { + return new Shard(shardSet, shardId); + } + + public static Shard from(String spec) { + return new Shard(spec); + } + + private final String spec; + + protected Shard(ShardSet shardSet, int shardId) { + this.spec = shardSet.getCore() + "~" + shardId; + } + + protected Shard(String spec) { + this.spec = spec; + } + + public org.alfresco.repo.index.shard.Shard toAlfrescoModel(Floc floc) { + org.alfresco.repo.index.shard.Shard shard = new org.alfresco.repo.index.shard.Shard(); + shard.setFloc(floc); + shard.setInstance(this.extractShardId()); + return shard; + } + + public String getSpec() { + return spec; + } + + public String extractShardSetCore() { + int pos = this.spec.indexOf('~'); + return this.spec.substring(0, pos); + } + + public int extractShardId() { + int pos = this.spec.indexOf('~'); + return Integer.parseInt(this.spec.substring(pos+1)); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Shard)) + return false; + Shard shard = (Shard) obj; + return this.spec.equals(shard.spec); + } + + @Override + public int hashCode() { + return this.spec.hashCode(); + } + + @Override + public String toString() { + return this.spec; + } + +} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardInstance.java b/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardInstance.java new file mode 100644 index 0000000..53aa456 --- /dev/null +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardInstance.java @@ -0,0 +1,64 @@ +package com.inteligr8.alfresco.asie.model; + +import java.io.Serializable; + +public class ShardInstance implements Serializable { + + private static final long serialVersionUID = 7455521296197234581L; + + public static ShardInstance from(Shard shard, SolrHost node) { + return new ShardInstance(shard, node); + } + + private final String spec; + + protected ShardInstance(Shard shard, SolrHost node) { + this.spec = shard.getSpec() + "~" + node.getSpec(); + } + + public org.alfresco.repo.index.shard.ShardInstance toAlfrescoModel(org.alfresco.repo.index.shard.Shard shard) { + SolrHost node = this.extractNode(); + + String core = shard.getFloc().getPropertyBag().get("coreName"); + + org.alfresco.repo.index.shard.ShardInstance shardInstance = new org.alfresco.repo.index.shard.ShardInstance(); + shardInstance.setHostName(node.getHostname()); + shardInstance.setPort(node.getPort()); + shardInstance.setBaseUrl(node.getPath() + "/" + core + "-" + shard.getInstance()); + shardInstance.setShard(shard); + return shardInstance; + } + + public String getSpec() { + return spec; + } + + public Shard extractShard() { + int pos = this.spec.indexOf('~'); + return Shard.from(this.spec.substring(0, pos)); + } + + public SolrHost extractNode() { + int pos = this.spec.indexOf('~'); + return SolrHost.from(this.spec.substring(pos+1)); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ShardInstance)) + return false; + ShardInstance shard = (ShardInstance) obj; + return this.spec.equals(shard.spec); + } + + @Override + public int hashCode() { + return this.spec.hashCode(); + } + + @Override + public String toString() { + return this.spec; + } + +} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardInstanceState.java b/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardInstanceState.java new file mode 100644 index 0000000..eb143c2 --- /dev/null +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardInstanceState.java @@ -0,0 +1,102 @@ +package com.inteligr8.alfresco.asie.model; + +import java.io.Serializable; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.Map.Entry; + +import org.alfresco.repo.index.shard.ShardInstance; +import org.alfresco.repo.index.shard.ShardState; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +public class ShardInstanceState implements Serializable, Comparable { + + private static final long serialVersionUID = 2893797002689889478L; + + public static ShardInstanceState from(ShardState shardState) { + return new ShardInstanceState(shardState); + } + + private final OffsetDateTime lastUpdated; + private final long lastIndexedChangeSetId; + private final OffsetDateTime lastIndexedChangeSetTime; + private final long lastIndexedTxId; + private final OffsetDateTime lastIndexedTxTime; + private transient Integer hash = null; + + private ShardInstanceState(ShardState shardState) { + this.lastUpdated = Instant.ofEpochMilli(shardState.getLastUpdated()).atOffset(ZoneOffset.UTC); + this.lastIndexedChangeSetId = shardState.getLastIndexedChangeSetId(); + this.lastIndexedChangeSetTime = Instant.ofEpochMilli(shardState.getLastIndexedChangeSetCommitTime()).atOffset(ZoneOffset.UTC); + this.lastIndexedTxId = shardState.getLastIndexedTxId(); + this.lastIndexedTxTime = Instant.ofEpochMilli(shardState.getLastIndexedTxCommitTime()).atOffset(ZoneOffset.UTC); + } + + public ShardState toAlfrescoModel(ShardInstance shardInstance) { + ShardState state = new ShardState(); + state.setLastIndexedChangeSetCommitTime(this.lastIndexedChangeSetTime.toInstant().toEpochMilli()); + state.setLastIndexedChangeSetId(this.lastIndexedChangeSetId); + state.setLastIndexedTxCommitTime(this.lastIndexedTxTime.toInstant().toEpochMilli()); + state.setLastIndexedTxId(this.lastIndexedTxId); + state.setLastUpdated(this.lastUpdated.toInstant().toEpochMilli()); + state.setShardInstance(shardInstance); + + for (Entry prop : shardInstance.getShard().getFloc().getPropertyBag().entrySet()) + if (prop.getKey().startsWith("shard.")) + state.getPropertyBag().put(prop.getKey(), prop.getValue()); + String core = shardInstance.getShard().getFloc().getPropertyBag().get("coreName"); + if (core != null) + state.getPropertyBag().put("coreName", core + "-" + shardInstance.getShard().getInstance()); + + return state; + } + + public OffsetDateTime getLastUpdated() { + return lastUpdated; + } + + public long getLastIndexedChangeSetId() { + return lastIndexedChangeSetId; + } + + public OffsetDateTime getLastIndexedChangeSetTime() { + return lastIndexedChangeSetTime; + } + + public long getLastIndexedTxId() { + return lastIndexedTxId; + } + + public OffsetDateTime getLastIndexedTxTime() { + return lastIndexedTxTime; + } + + @Override + public int compareTo(ShardInstanceState o) { + return -this.lastUpdated.compareTo(o.lastUpdated); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ShardInstanceState)) + return false; + ShardInstanceState snss = (ShardInstanceState) obj; + + return this.lastIndexedChangeSetId == snss.lastIndexedChangeSetId && + this.lastIndexedTxId == snss.lastIndexedTxId; + } + + @Override + public int hashCode() { + if (this.hash == null) { + this.hash = new HashCodeBuilder() + .append(this.lastIndexedTxId) + .append(this.lastIndexedChangeSetId) + .build(); + } + + return this.hash.intValue(); + } + +} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardSet.java b/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardSet.java index 348db29..811a810 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardSet.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardSet.java @@ -1,56 +1,194 @@ package com.inteligr8.alfresco.asie.model; import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Matcher; +import java.util.HashSet; +import java.util.Set; import java.util.regex.Pattern; import org.alfresco.repo.index.shard.Floc; import org.alfresco.repo.index.shard.ShardMethodEnum; import org.alfresco.repo.index.shard.ShardState; -import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.util.collections.CollectionUtils; +import org.apache.commons.collections4.map.CompositeMap; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; + +import com.inteligr8.alfresco.asie.SimpleCaster; public class ShardSet implements Serializable { private static final long serialVersionUID = -8891094367429601316L; - - /** - * Examples: - * - * MOD_ACL_ID - * ACL_ID - * DB_ID - * DB_ID_RANGE;range:0-20000 - * DATE;key:cm:created - * DATE;key:cm:created;date.grouping:3 - * PROPERTY;key:cm:created;regex:^d{4} - */ - private static final Pattern shardSetPattern = Pattern.compile("([A-Z]+)(;fulltext)?(;([a-z]+):([^;]+))?(;([a-z]+):([^;]+))?"); + private static final String DEFAULT_SOLR_TEMPLATE = "rerank"; - private final ShardMethodEnum method; - private final boolean hasContent; - private final Map config; - private transient Integer hash; - - public ShardSet(Floc floc, ShardState anyShardNode) { - this.method = floc.getShardMethod(); - this.hasContent = floc.hasContent(); - this.config = (floc.getPropertyBag().isEmpty() && anyShardNode != null) ? anyShardNode.getPropertyBag() : floc.getPropertyBag(); + public static ShardSet from(Floc floc, ShardState anyShardState) { + return new ShardSet(floc, anyShardState); } - public ShardSet(String shardSetSpec) { - Matcher matcher = shardSetPattern.matcher(shardSetSpec); - if (!matcher.find()) - throw new IllegalArgumentException("The shard set '" + shardSetSpec + "' is not properly formatted"); - - this.method = ShardMethodEnum.valueOf(matcher.group(1)); - this.hasContent = ";fulltext".equals(matcher.group(2)); - this.config = new HashMap<>(); - for (int g = 3; g < matcher.groupCount(); g += 3) - if (matcher.group(g) != null) - this.config.put("shard." + matcher.group(g+1), matcher.group(g+2)); + public static ShardSet from(String coreName, String spec) { + return new ShardSet(coreName, spec); + } + + private final String core; + private final ShardMethodEnum method; + private final boolean hasContent; + private final String template; + private final Set storeRefs; + private final Short shards; + private final Pair range; + private final Byte dateGrouping; + private final String prefixedProperty; + private final Pattern regex; + private transient String spec; + + private ShardSet(Floc floc, ShardState anyShardNode) { + String shardCoreName = anyShardNode.getPropertyBag().get("coreName"); + int lastDash = shardCoreName.lastIndexOf('-'); + this.core = shardCoreName.substring(0, lastDash); + + this.method = floc.getShardMethod(); + this.hasContent = floc.hasContent(); + this.template = floc.getTemplate(); + this.storeRefs = floc.getStoreRefs(); + CompositeMap propbag = new CompositeMap<>(floc.getPropertyBag(), anyShardNode.getPropertyBag()); + + Short shards = null; + Pair range = null; + Byte dateGrouping = null; + String prefixedProperty = null; + String regex = null; + + switch (this.method) { + case DB_ID_RANGE: + range = this.strToRange(propbag.get("shard.range")); + break; + case DATE: + dateGrouping = SimpleCaster.transform(propbag.get("shard.date.grouping"), Byte.class); + case PROPERTY: + case EXPLICIT_ID: + prefixedProperty = StringUtils.trimToNull(propbag.get("shard.key")); + regex = StringUtils.trimToNull(propbag.get("shard.regex")); + default: + shards = (short) floc.getNumberOfShards(); + } + + this.range = range; + this.shards = shards; + this.dateGrouping = dateGrouping; + this.prefixedProperty = prefixedProperty; + this.regex = regex == null ? null : Pattern.compile(regex); + } + + public Floc toAlfrescoModel() { + Floc floc = new Floc(); + floc.setShardMethod(this.method); + floc.setHasContent(this.hasContent); + floc.setTemplate(this.template); + floc.setStoreRefs(new HashSet<>(this.storeRefs)); + floc.getPropertyBag().put("coreName", this.core); + + switch (this.method) { + case DB_ID_RANGE: + floc.getPropertyBag().put("shard.range", this.range.getLeft() + "-" + this.range.getRight()); + break; + case DATE: + if (this.dateGrouping != null) + floc.getPropertyBag().put("shard.date.grouping", this.dateGrouping.toString()); + case PROPERTY: + case EXPLICIT_ID: + floc.getPropertyBag().put("shard.key", this.prefixedProperty); + if (this.regex != null) + floc.getPropertyBag().put("shard.regex", this.regex.pattern()); + default: + if (this.shards != null) + floc.setNumberOfShards(this.shards.intValue()); + } + + return floc; + } + + private ShardSet(String coreName, String shardSetSpec) { + String[] parts = shardSetSpec.split("[;|_]"); + if (parts.length == 0) + throw new IllegalArgumentException(); + + this.core = coreName; + this.method = ShardMethodEnum.valueOf(parts[0].toUpperCase()); + + boolean hasContent = false; + String template = DEFAULT_SOLR_TEMPLATE; + StoreRef storeRef = StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; + Pair range = null; + Short shards = null; + Byte dateGrouping = null; + String prefixedProperty = null; + String regex = null; + + for (int i = 1; i < parts.length; i++) { + int colon = parts[i].indexOf(":"); + String fieldName = colon < 0 ? parts[i] : parts[i].substring(0, colon); + String fieldValue = colon < 0 ? null : parts[i].substring(colon+1); + + switch (fieldName) { + case "txt": + case "text": + case "fulltext": + case "content": + case "hasContent": + case "hasText": + hasContent = true; + break; + case "t": + case "template": + template = fieldValue; + break; + case "sref": + case "storeRef": + storeRef = new StoreRef(fieldValue); + break; + case "s": + case "shards": + shards = SimpleCaster.transform(fieldValue, Short.class); + break; + case "range": + range = this.strToRange(fieldValue); + break; + case "date.grouping": + dateGrouping = SimpleCaster.transform(fieldValue, Byte.class); + break; + case "k": + case "key": + prefixedProperty = fieldValue; + break; + case "regex": + regex = fieldValue; + break; + default: + throw new IllegalArgumentException(); + } + } + + this.hasContent = hasContent; + this.template = template; + this.storeRefs = CollectionUtils.asSet(storeRef); + this.shards = shards; + this.range = range; + this.dateGrouping = dateGrouping; + this.prefixedProperty = prefixedProperty; + this.regex = regex == null ? null : Pattern.compile(regex); + } + + private Pair strToRange(String str) { + str = StringUtils.trimToNull(str); + if (str == null) + return null; + + String[] rangeValues = str.split("-"); + return Pair.of(Long.valueOf(rangeValues[0]), Long.valueOf(rangeValues[1])); + } + + public String getCore() { + return core; } public ShardMethodEnum getMethod() { @@ -61,35 +199,70 @@ public class ShardSet implements Serializable { return hasContent; } + public String getTemplate() { + return template; + } + + public Set getStoreRefs() { + return storeRefs; + } + + public Short getShards() { + return shards; + } + + public Pair getRange() { + return range; + } + + public Byte getDateGrouping() { + return dateGrouping; + } + + public String getPrefixedProperty() { + return prefixedProperty; + } + + public Pattern getRegex() { + return regex; + } + public String toSpec() { - StringBuilder spec = new StringBuilder(this.method.toString()); - if (this.hasContent) - spec.append(";fulltext"); - for (Entry c : this.config.entrySet()) { - if (!c.getKey().startsWith("shard.")) - continue; - spec.append(';').append(c.getKey().substring(6)).append(':').append(c.getValue()); - } - return spec.toString(); - } - - public Map getConfig() { - return config; - } - - public boolean isFor(ShardState shardState) { - return this.method.equals(shardState.getShardInstance().getShard().getFloc().getShardMethod()) && - this.hasContent == shardState.getShardInstance().getShard().getFloc().hasContent() && - this.isConfigurationFor(shardState.getPropertyBag()); - } - - public boolean isConfigurationFor(Map propertyBag) { - for (Entry config : this.config.entrySet()) { - if (config.getValue() == null || !config.getValue().equals(propertyBag.get(config.getKey()))) - return false; + if (this.spec == null) { + StringBuilder spec = new StringBuilder(this.method.toString()); + if (this.hasContent) + spec.append(";txt"); + spec.append(";t:").append(this.template); + spec.append(";sref:").append(StringUtils.join(this.storeRefs, ',')); + if (this.shards != null) + spec.append(";s:").append(this.shards); + if (this.range != null) + spec.append(";range:").append(this.range.getLeft()).append('-').append(this.range.getRight()); + if (this.dateGrouping != null) + spec.append(";date.grouping:").append(this.dateGrouping); + if (this.prefixedProperty != null) + spec.append(";k:").append(this.prefixedProperty); + if (this.regex != null) + spec.append(";regex:").append(this.regex); + this.spec = spec.toString(); } - return true; + return spec; + } + + public boolean contains(ShardState shardState) { + Floc floc = shardState.getShardInstance().getShard().getFloc(); + CompositeMap propbag = new CompositeMap<>(shardState.getPropertyBag(), floc.getPropertyBag()); + + return this.method.equals(floc.getShardMethod()) && + this.hasContent == floc.hasContent() && + StringUtils.equals(this.template, floc.getTemplate()) && + this.storeRefs.equals(floc.getStoreRefs()) && + this.equals(this.shards, floc.getNumberOfShards()) && + this.equals(this.range, this.strToRange(propbag.get("shard.range"))) && + this.equals(this.dateGrouping, propbag.get("shard.date.grouping")) && + StringUtils.equals(this.prefixedProperty, propbag.get("shard.key")) && + this.equals(this.regex, propbag.get("shard.regex")); } @Override @@ -98,21 +271,34 @@ public class ShardSet implements Serializable { return false; ShardSet shardSet = (ShardSet) obj; - return this.method.equals(shardSet.method) && this.config.equals(shardSet.config); + return this.core.equals(shardSet.core); + } + + private boolean equals(Pattern p1, String s2) { + s2 = StringUtils.trimToNull(s2); + if (p1 == null) { + return s2 == null; + } else { + return p1.pattern().equals(s2); + } + } + + private boolean equals(T t1, T t2) { + if (t1 == null) { + return t2 == null; + } else { + return t1.equals(t2); + } } @Override public int hashCode() { - if (this.hash == null) { - this.hash = new HashCodeBuilder().append(this.method).append(this.hasContent).append(this.config).build(); - } - - return this.hash; + return this.core.hashCode(); } @Override public String toString() { - return this.toSpec(); + return this.core; } } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/SolrHost.java b/shared/src/main/java/com/inteligr8/alfresco/asie/model/SolrHost.java new file mode 100644 index 0000000..b935e97 --- /dev/null +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/model/SolrHost.java @@ -0,0 +1,92 @@ +package com.inteligr8.alfresco.asie.model; + +import java.io.Serializable; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.alfresco.repo.index.shard.ShardInstance; + +public class SolrHost implements Serializable { + + private static final long serialVersionUID = -8834744746109388928L; + private static final Pattern PATTERN = Pattern.compile("([^:]+):([0-9]+)([^0-9]?.*)"); + + public static SolrHost from(ShardInstance shardNode) { + return new SolrHost(shardNode); + } + + public static SolrHost from(String spec) { + return new SolrHost(spec); + } + + private final String spec; + private final String hostname; + private final int port; + private final String path; + + protected SolrHost(ShardInstance shardNode) { + this.hostname = shardNode.getHostName(); + this.port = shardNode.getPort(); + + // baseUrl is to the shard; we want to the node, so exclude the core + int lastSlash = shardNode.getBaseUrl().lastIndexOf('/'); + this.path = shardNode.getBaseUrl().substring(0, lastSlash); + + this.spec = this.hostname + ":" + this.port + this.path; + } + + protected SolrHost(String spec) { + this.spec = spec; + + Matcher matcher = PATTERN.matcher(spec); + this.hostname = matcher.group(1); + this.port = Integer.parseInt(matcher.group(2)); + this.path = matcher.group(3); + } + + public String getSpec() { + return this.spec; + } + + public String getHostname() { + return this.hostname; + } + + public int getPort() { + return this.port; + } + + public String getPath() { + return this.path; + } + + public URL toUrl(String protocol) { + try { + return new URL(protocol + "://" + this.hostname + ':' + this.port + this.path); + } catch (MalformedURLException mue) { + throw new IllegalArgumentException(mue.getMessage()); + } + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SolrHost)) + return false; + + SolrHost shardNode = (SolrHost) obj; + return this.spec.equals(shardNode.spec); + } + + @Override + public int hashCode() { + return this.spec.hashCode(); + } + + @Override + public String toString() { + return this.spec; + } + +} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieNodeWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieNodeWebScript.java index b44ddb5..e40244b 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieNodeWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieNodeWebScript.java @@ -1,9 +1,8 @@ package com.inteligr8.alfresco.asie.rest; import java.io.IOException; -import java.util.Set; +import java.util.Map; -import org.alfresco.repo.index.shard.ShardState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -12,7 +11,10 @@ import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; import org.springframework.http.HttpStatus; -import com.inteligr8.alfresco.asie.service.ShardDiscoveryService; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; +import com.inteligr8.alfresco.asie.spi.ShardDiscoveryService; public abstract class AbstractAsieNodeWebScript extends AbstractAsieShardableWebScript { @@ -36,16 +38,17 @@ public abstract class AbstractAsieNodeWebScript extends AbstractAsieShardableWeb protected void execute(WebScriptRequest req, WebScriptResponse res, String nodeHostname, int nodePort) throws IOException { this.logger.trace("execute({}, {})", nodeHostname, nodePort); - - Set shardsOnNode = this.sds.findByNode(nodeHostname, nodePort); + + SolrHost node = this.sds.findNode(nodeHostname, nodePort); + Map> shardsOnNode = this.sds.findByNode(node); if (shardsOnNode == null || shardsOnNode.isEmpty()) throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE node could not be found"); - this.execute(req, res, shardsOnNode); + this.execute(req, res, node, shardsOnNode); } - protected void execute(WebScriptRequest req, WebScriptResponse res, Set registeredNodeShards) throws IOException { - this.logger.trace("execute({})", registeredNodeShards.size()); + protected void execute(WebScriptRequest req, WebScriptResponse res, SolrHost node, Map> shardSetShardStates) throws IOException { + this.logger.trace("execute({})", shardSetShardStates.size()); // made to be optionally overridden } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieShardWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieShardWebScript.java index 81e672f..00c8deb 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieShardWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieShardWebScript.java @@ -1,9 +1,9 @@ package com.inteligr8.alfresco.asie.rest; import java.io.IOException; -import java.util.Set; +import java.util.List; -import org.alfresco.repo.index.shard.ShardState; +import org.alfresco.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -13,7 +13,9 @@ import org.springframework.extensions.webscripts.WebScriptResponse; import org.springframework.http.HttpStatus; import com.inteligr8.alfresco.asie.model.ShardSet; -import com.inteligr8.alfresco.asie.service.ShardDiscoveryService; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; +import com.inteligr8.alfresco.asie.spi.ShardDiscoveryService; public abstract class AbstractAsieShardWebScript extends AbstractAsieShardableWebScript { @@ -26,21 +28,24 @@ public abstract class AbstractAsieShardWebScript extends AbstractAsieShardableWe public void executeAuthorized(WebScriptRequest req, WebScriptResponse res) throws IOException { this.logger.trace("execute()"); - ShardSet shardSet = this.getRequiredPathParameter(req, "shardSet", ShardSet.class); - this.logger.debug("Parsed shard set: {}", shardSet); + String coreName = this.getRequiredPathParameter(req, "shardCore"); int shardId = this.getRequiredPathParameter(req, "shardId", Integer.class); try { - Set registeredShardNodes = this.sds.findByShard(shardSet, shardId); - if (registeredShardNodes == null || registeredShardNodes.isEmpty()) - throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard set or shard could not be found"); + ShardSet shardSet = this.sds.findSetByCore(coreName); + if (shardSet == null) + throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard set could not be found"); - this.execute(req, res, registeredShardNodes); + List> nodeShardStates = this.sds.findNodeStatesByShard(shardSet, shardId); + if (nodeShardStates == null || nodeShardStates.isEmpty()) + throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard could not be found"); + + this.execute(req, res, shardId, shardSet, nodeShardStates); } catch (IllegalArgumentException iae) { throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), iae.getMessage()); } } - protected abstract void execute(WebScriptRequest req, WebScriptResponse res, Set registeredShardNodes) throws IOException; + protected abstract void execute(WebScriptRequest req, WebScriptResponse res, int shardId, ShardSet shardSet, List> nodeShardStates) throws IOException; } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieShardableWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieShardableWebScript.java index a3bf089..2b4d3d7 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieShardableWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/AbstractAsieShardableWebScript.java @@ -57,7 +57,7 @@ public abstract class AbstractAsieShardableWebScript extends AbstractAsieWebScri try { SolrShardHashSampleType type = SolrShardHashSampleType.valueOf(matcher.group(1)); - int shards = Integer.parseInt(matcher.group(2)); + short shards = Short.parseShort(matcher.group(2)); return this.createSampleHashTable(type, shards); } catch (NumberFormatException nfe) { // this should never happen, because of the regex @@ -67,7 +67,7 @@ public abstract class AbstractAsieShardableWebScript extends AbstractAsieWebScri } } - protected SolrShardHashTable createSampleHashTable(SolrShardHashSampleType sampleType, int shards) { + protected SolrShardHashTable createSampleHashTable(SolrShardHashSampleType sampleType, short shards) { int thisYear = Year.now().getValue(); switch (sampleType) { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetBackupNodeWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetBackupNodeWebScript.java index 800ae7e..ab5c9da 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetBackupNodeWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetBackupNodeWebScript.java @@ -1,19 +1,21 @@ package com.inteligr8.alfresco.asie.rest; import java.io.IOException; -import java.util.Set; +import java.util.Collections; +import java.util.List; -import org.alfresco.repo.index.shard.ShardState; +import org.alfresco.util.Pair; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; -import com.inteligr8.alfresco.asie.model.Node; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; import com.inteligr8.alfresco.asie.service.ShardBackupService; +import com.inteligr8.alfresco.asie.spi.ShardDiscoveryService; @Component(value = "webscript.com.inteligr8.alfresco.asie.backupNode.get") public class GetBackupNodeWebScript extends AbstractAsieShardWebScript { @@ -22,15 +24,15 @@ public class GetBackupNodeWebScript extends AbstractAsieShardWebScript { private ShardBackupService sbs; @Override - public void execute(WebScriptRequest req, WebScriptResponse res, Set shardNodes) throws IOException { - if (shardNodes.isEmpty()) - throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard state could not be found"); - - Node node = this.sbs.fetchNode(shardNodes); + public void execute(WebScriptRequest req, WebScriptResponse res, int shardId, ShardSet shardSet, List> nodeShardStates) throws IOException { + Collections.sort(nodeShardStates, new ShardDiscoveryService.ShardedNodeShardStateComparator()); + SolrHost mostRecentNode = nodeShardStates.iterator().next().getFirst(); + + SolrHost backupNode = this.sbs.selectNode(shardSet, shardId, mostRecentNode); res.setContentType(MediaType.APPLICATION_JSON_VALUE); res.setContentEncoding("utf-8"); - this.getObjectMapper().writeValue(res.getWriter(), node.getId()); + this.getObjectMapper().writeValue(res.getWriter(), backupNode.getSpec()); } } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetLeadNodeWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetLeadNodeWebScript.java index 60faaec..803dbd8 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetLeadNodeWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetLeadNodeWebScript.java @@ -1,10 +1,9 @@ package com.inteligr8.alfresco.asie.rest; import java.io.IOException; -import java.util.Set; +import java.util.List; -import org.alfresco.repo.index.shard.ShardInstance; -import org.alfresco.repo.index.shard.ShardState; +import org.alfresco.util.Pair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; @@ -13,7 +12,9 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; -import com.inteligr8.alfresco.asie.model.Node; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; import com.inteligr8.alfresco.asie.spi.ShardDiscoveryService; @Component(value = "webscript.com.inteligr8.alfresco.asie.leadNode.get") @@ -23,17 +24,14 @@ public class GetLeadNodeWebScript extends AbstractAsieShardWebScript { private ShardDiscoveryService sds; @Override - public void execute(WebScriptRequest req, WebScriptResponse res, Set shardNodesCache) throws IOException { - if (shardNodesCache.isEmpty()) - throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard state could not be found"); - - ShardInstance latestNode = this.sds.computeLeadShard(shardNodesCache); + public void execute(WebScriptRequest req, WebScriptResponse res, int shardId, ShardSet shardSet, List> nodeShardStates) throws IOException { + SolrHost latestNode = this.sds.computeLeadNode(nodeShardStates); if (latestNode == null) - throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard state could not be found"); + throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE node could not be found"); res.setContentType(MediaType.APPLICATION_JSON_VALUE); res.setContentEncoding("utf-8"); - this.getObjectMapper().writeValue(res.getWriter(), new Node(latestNode).getId()); + this.getObjectMapper().writeValue(res.getWriter(), latestNode.getSpec()); } } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetNodeWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetNodeWebScript.java index 3620d31..9d49887 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetNodeWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetNodeWebScript.java @@ -1,18 +1,17 @@ package com.inteligr8.alfresco.asie.rest; import java.io.IOException; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.Set; +import java.util.Map; +import java.util.Map.Entry; -import org.alfresco.repo.index.shard.ShardInstance; -import org.alfresco.repo.index.shard.ShardState; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; import org.springframework.stereotype.Component; import com.inteligr8.alfresco.asie.compute.SolrShardHashTable; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; import com.inteligr8.alfresco.asie.rest.model.NodeInfo; import com.inteligr8.alfresco.asie.rest.model.NodeShardInfo; import com.inteligr8.alfresco.asie.rest.model.ShardInfo; @@ -22,32 +21,32 @@ import com.inteligr8.alfresco.asie.rest.model.ShardSetInfo; public class GetNodeWebScript extends AbstractAsieNodeWebScript { @Override - protected void execute(WebScriptRequest req, WebScriptResponse res, Set registeredNodeShards) throws IOException { - ShardState anyRegisteredNodeShard = registeredNodeShards.iterator().next(); - ShardInstance registeredNode = anyRegisteredNodeShard.getShardInstance(); - int maxShards = registeredNode.getShard().getFloc().getNumberOfShards(); - + protected void execute(WebScriptRequest req, WebScriptResponse res, SolrHost node, Map> shardSetShardStates) throws IOException { SolrShardHashSampleType sampleHashType = this.getOptionalQueryParameter(req, "sampleHashType", SolrShardHashSampleType.class); - SolrShardHashTable sampleHashTable = sampleHashType == null ? null : this.createSampleHashTable(sampleHashType, maxShards); - NodeInfo node = new NodeShardInfo(registeredNode); - - for (ShardState registeredNodeShard : registeredNodeShards) { - ShardInfo shard = new ShardInfo(); - shard.setId(registeredNodeShard.getShardInstance().getShard().getInstance()); - shard.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(registeredNodeShard.getLastIndexedTxCommitTime()), ZoneOffset.UTC)); - shard.setTxsCompleted(registeredNodeShard.getLastIndexedTxId()); - - shard.setShardSet(new ShardSetInfo(registeredNodeShard.getShardInstance().getShard().getFloc(), registeredNodeShard)); - if (sampleHashTable != null) - this.addShardHashSamples(shard, sampleHashTable); - - node.getShards().put(shard.getId(), shard); - } + NodeInfo nodeResponse = NodeShardInfo.from(node); + + for (Entry> shardSet : shardSetShardStates.entrySet()) { + Short maxShards = shardSet.getKey().getShards(); + SolrShardHashTable sampleHashTable = null; + if (sampleHashType != null && maxShards != null) + sampleHashTable = this.createSampleHashTable(sampleHashType, maxShards); + + ShardSetInfo shardSetResponse = ShardSetInfo.from(shardSet.getKey()); + + for (Entry shard : shardSet.getValue().entrySet()) { + ShardInfo shardResponse = ShardInfo.from(shard.getKey(), shard.getValue()); + shardResponse.setShardSet(shardSetResponse); + if (sampleHashTable != null) + this.addShardHashSamples(shardResponse, sampleHashTable); + + nodeResponse.getShards().put(shardResponse.getId(), shardResponse); + } + } res.setContentType("application/json"); res.setContentEncoding("utf-8"); - this.getObjectMapper().writeValue(res.getWriter(), node); + this.getObjectMapper().writeValue(res.getWriter(), nodeResponse); } } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetNodesWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetNodesWebScript.java index 0e47169..195d229 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetNodesWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetNodesWebScript.java @@ -8,6 +8,7 @@ import java.util.TreeMap; import org.alfresco.repo.index.shard.Floc; import org.alfresco.repo.index.shard.Shard; +import org.alfresco.repo.index.shard.ShardMethodEnum; import org.alfresco.repo.index.shard.ShardState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,7 +19,9 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import com.inteligr8.alfresco.asie.compute.SolrShardHashTable; -import com.inteligr8.alfresco.asie.model.Node; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; import com.inteligr8.alfresco.asie.rest.model.NodeInfo; import com.inteligr8.alfresco.asie.rest.model.NodeShardInfo; import com.inteligr8.alfresco.asie.rest.model.ShardInfo; @@ -39,34 +42,44 @@ public class GetNodesWebScript extends AbstractAsieShardableWebScript { SolrShardHashSampleType sampleHashType = this.getOptionalQueryParameter(req, "sampleHashType", SolrShardHashSampleType.class); - Map nodes = new TreeMap<>(); + Map nodesResponse = new TreeMap<>(); for (Entry>> floc : flocs.entrySet()) { - int maxShards = floc.getKey().getNumberOfShards(); + Short maxShards = floc.getKey().getShardMethod().equals(ShardMethodEnum.DB_ID_RANGE) ? null : (short) floc.getKey().getNumberOfShards(); + SolrShardHashTable sampleHashTable = null; + if (sampleHashType != null && maxShards != null) + sampleHashTable = this.createSampleHashTable(sampleHashType, maxShards); - SolrShardHashTable sampleHashTable = sampleHashType == null ? null : this.createSampleHashTable(sampleHashType, maxShards); + ShardSetInfo shardSetResponse = null; for (Entry> registeredShards : floc.getValue().entrySet()) { for (ShardState registeredShardNode : registeredShards.getValue()) { - String nodeId = new Node(registeredShardNode.getShardInstance()).getId(); - NodeInfo node = nodes.get(nodeId); - if (node == null) { - node = new NodeShardInfo(registeredShardNode.getShardInstance()); - nodes.put(node.getId(), node); + if (shardSetResponse == null) { + ShardSet shardSet = ShardSet.from(floc.getKey(), registeredShardNode); + shardSetResponse = ShardSetInfo.from(shardSet); } - ShardInfo shard = new ShardInfo(registeredShardNode); - shard.setShardSet(new ShardSetInfo(floc.getKey(), registeredShardNode)); + SolrHost node = SolrHost.from(registeredShardNode.getShardInstance()); + String nodeSpec = node.getSpec(); + NodeInfo nodeResponse = nodesResponse.get(nodeSpec); + if (nodeResponse == null) { + nodeResponse = NodeShardInfo.from(node); + nodesResponse.put(nodeResponse.getId(), nodeResponse); + } + + ShardInstanceState nodeShardState = ShardInstanceState.from(registeredShardNode); + ShardInfo shardResponse = ShardInfo.from(registeredShards.getKey().getInstance(), nodeShardState); + shardResponse.setShardSet(shardSetResponse); if (sampleHashTable != null) - this.addShardHashSamples(shard, sampleHashTable); - node.getShards().put(shard.getId(), shard); + this.addShardHashSamples(shardResponse, sampleHashTable); + nodeResponse.getShards().put(shardResponse.getId(), shardResponse); } } } res.setContentType("application/json"); res.setContentEncoding("utf-8"); - this.getObjectMapper().writeValue(res.getWriter(), nodes); + this.getObjectMapper().writeValue(res.getWriter(), nodesResponse); } } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetPropertyHashShardsWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetPropertyHashShardsWebScript.java index 0139460..7ed169e 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetPropertyHashShardsWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetPropertyHashShardsWebScript.java @@ -1,11 +1,7 @@ package com.inteligr8.alfresco.asie.rest; import java.io.IOException; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -14,10 +10,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; -import org.alfresco.repo.index.shard.Floc; -import org.alfresco.repo.index.shard.Shard; import org.alfresco.repo.index.shard.ShardMethodEnum; -import org.alfresco.repo.index.shard.ShardState; import org.alfresco.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,11 +23,14 @@ import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import com.inteligr8.alfresco.asie.compute.SolrShardHashTable; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; import com.inteligr8.alfresco.asie.rest.model.NodeInfo; import com.inteligr8.alfresco.asie.rest.model.PropertyHashShardSetInfo; import com.inteligr8.alfresco.asie.rest.model.ShardInfo; import com.inteligr8.alfresco.asie.rest.model.ShardNodeInfo; -import com.inteligr8.alfresco.asie.service.ShardDiscoveryService; +import com.inteligr8.alfresco.asie.spi.ShardDiscoveryService; @Component(value = "webscript.com.inteligr8.alfresco.asie.propertyHashShards.get") public class GetPropertyHashShardsWebScript extends AbstractAsieShardableWebScript { @@ -55,19 +51,18 @@ public class GetPropertyHashShardsWebScript extends AbstractAsieShardableWebScri List values = this.getOptionalQueryParameterAsList(req); this.validateParameters(min, max, values); - List shardSets = new LinkedList<>(); - - Collection>>> flocs = this.sds.findByShardMethod(ShardMethodEnum.PROPERTY); - if (flocs.isEmpty()) + List shardSetsResponse = new LinkedList<>(); + + Set shardSets = this.sds.findSetsByShardMethod(ShardMethodEnum.PROPERTY); + if (shardSets.isEmpty()) throw new WebScriptException(HttpStatus.NO_CONTENT.value(), "There are no property-based shards"); - for (Pair>> floc : flocs) { - ShardState anyShardNode = this.getAnyShardNode(floc.getSecond()); - PropertyHashShardSetInfo shardSet = new PropertyHashShardSetInfo(floc.getFirst(), anyShardNode); - shardSet.setShards(new TreeMap<>()); + for (ShardSet shardSet : shardSets) { + PropertyHashShardSetInfo shardSetResponse = PropertyHashShardSetInfo.from(shardSet); + shardSetResponse.setShards(new TreeMap<>()); - int maxShards = floc.getFirst().getNumberOfShards(); - SolrShardHashTable sampleHashTable = this.createSampleHashTable(sampleHashType, maxShards); + Short shardCount = shardSet.getShards(); + SolrShardHashTable sampleHashTable = this.createSampleHashTable(sampleHashType, shardCount); Map> shardToHashMap = new HashMap<>(); @@ -83,39 +78,24 @@ public class GetPropertyHashShardsWebScript extends AbstractAsieShardableWebScri } } - for (Entry> shardCache : floc.getSecond().entrySet()) { - ShardInfo shard = new ShardInfo(); - shard.setId(shardCache.getKey().getInstance()); - shard.setNodes(new HashMap<>()); - - for (ShardState shardNodeCache : shardCache.getValue()) { - if (shard.getTxsCompleted() == null || shard.getTxsCompleted().longValue() < shardNodeCache.getLastIndexedTxId()) { - shard.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(shardNodeCache.getLastIndexedTxCommitTime()), ZoneOffset.UTC)); - shard.setTxsCompleted(shardNodeCache.getLastIndexedTxId()); - } + for (Entry> shard : this.sds.findLatestNodeStates(shardSet).entrySet()) { + ShardInfo shardResponse = ShardInfo.from(shard.getKey(), shard.getValue().getSecond()); + shardResponse.setNodes(new HashMap<>()); - NodeInfo node = new ShardNodeInfo(shardNodeCache); - shard.getNodes().put(node.getId(), node); - } + NodeInfo nodeResponse = ShardNodeInfo.from(shard.getValue().getFirst(), shard.getValue().getSecond()); + shardResponse.getNodes().put(nodeResponse.getId(), nodeResponse); - List hashedValues = shardToHashMap.get(shard.getId()); + List hashedValues = shardToHashMap.get(shardResponse.getId()); if (hashedValues != null) for (Object hashedValue : hashedValues) - shardSet.getShards().put(hashedValue, shard); + shardSetResponse.getShards().put(hashedValue, shardResponse); } - shardSets.add(shardSet); + shardSetsResponse.add(shardSetResponse); } res.setContentType(MediaType.APPLICATION_JSON_VALUE); res.setContentEncoding("utf-8"); - this.getObjectMapper().writeValue(res.getWriter(), shardSets); - } - - private ShardState getAnyShardNode(Map> shards) { - for (Set shardNodes : shards.values()) - for (ShardState shardNode : shardNodes) - return shardNode; - return null; + this.getObjectMapper().writeValue(res.getWriter(), shardSetsResponse); } private List getOptionalQueryParameterAsList(WebScriptRequest req) { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetShardWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetShardWebScript.java index 197fb37..001bab2 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetShardWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetShardWebScript.java @@ -1,20 +1,19 @@ package com.inteligr8.alfresco.asie.rest; import java.io.IOException; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.Set; +import java.util.List; import java.util.TreeMap; -import org.alfresco.repo.index.shard.Shard; -import org.alfresco.repo.index.shard.ShardState; +import org.alfresco.util.Pair; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import com.inteligr8.alfresco.asie.compute.SolrShardHashTable; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; import com.inteligr8.alfresco.asie.rest.model.NodeInfo; import com.inteligr8.alfresco.asie.rest.model.ShardInfo; import com.inteligr8.alfresco.asie.rest.model.ShardNodeInfo; @@ -24,34 +23,35 @@ import com.inteligr8.alfresco.asie.rest.model.ShardSetInfo; public class GetShardWebScript extends AbstractAsieShardWebScript { @Override - public void execute(WebScriptRequest req, WebScriptResponse res, Set registeredShardNodes) throws IOException { - ShardState aRegisteredShardNode = registeredShardNodes.iterator().next(); - Shard registeredShard = aRegisteredShardNode.getShardInstance().getShard(); - int maxShards = registeredShard.getFloc().getNumberOfShards(); - + public void execute(WebScriptRequest req, WebScriptResponse res, int shardId, ShardSet shardSet, List> nodeShardStates) throws IOException { SolrShardHashSampleType sampleHashType = this.getOptionalQueryParameter(req, "sampleHashType", SolrShardHashSampleType.class); - SolrShardHashTable sampleHashTable = sampleHashType == null ? null : this.createSampleHashTable(sampleHashType, maxShards); - ShardInfo shard = new ShardInfo(); - shard.setId(registeredShard.getInstance()); - shard.setShardSet(new ShardSetInfo(registeredShard.getFloc(), aRegisteredShardNode)); - shard.setNodes(new TreeMap<>()); + Short maxShards = shardSet.getShards(); + SolrShardHashTable sampleHashTable = null; + if (sampleHashType != null && maxShards != null) + sampleHashTable = this.createSampleHashTable(sampleHashType, maxShards); + + ShardSetInfo shardSetResponse = ShardSetInfo.from(shardSet); + + ShardInfo shardResponse = ShardInfo.from(shardId); + shardResponse.setShardSet(shardSetResponse); + shardResponse.setNodes(new TreeMap<>()); if (sampleHashTable != null) - this.addShardHashSamples(shard, sampleHashTable); + this.addShardHashSamples(shardResponse, sampleHashTable); - for (ShardState registeredShardNode : registeredShardNodes) { - if (shard.getTxsCompleted() == null || shard.getTxsCompleted().longValue() < registeredShardNode.getLastIndexedTxId()) { - shard.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(registeredShardNode.getLastIndexedTxCommitTime()), ZoneOffset.UTC)); - shard.setTxsCompleted(registeredShardNode.getLastIndexedTxId()); + for (Pair nodeShardState : nodeShardStates) { + if (shardResponse.getTxsCompleted() == null || shardResponse.getTxsCompleted().longValue() < nodeShardState.getSecond().getLastIndexedTxId()) { + shardResponse.setLatestTx(nodeShardState.getSecond().getLastIndexedTxTime()); + shardResponse.setTxsCompleted(nodeShardState.getSecond().getLastIndexedTxId()); } - NodeInfo node = new ShardNodeInfo(registeredShardNode); - shard.getNodes().put(node.getId(), node); + NodeInfo node = ShardNodeInfo.from(nodeShardState.getFirst(), nodeShardState.getSecond()); + shardResponse.getNodes().put(node.getId(), node); } res.setContentType(MediaType.APPLICATION_JSON_VALUE); res.setContentEncoding("utf-8"); - this.getObjectMapper().writeValue(res.getWriter(), shard); + this.getObjectMapper().writeValue(res.getWriter(), shardResponse); } } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetShardsWebScript.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetShardsWebScript.java index 8a5a4b1..ae6585b 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetShardsWebScript.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/GetShardsWebScript.java @@ -22,6 +22,9 @@ import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import com.inteligr8.alfresco.asie.compute.SolrShardHashTable; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; import com.inteligr8.alfresco.asie.rest.model.NodeInfo; import com.inteligr8.alfresco.asie.rest.model.ShardInfo; import com.inteligr8.alfresco.asie.rest.model.ShardNodeInfo; @@ -42,42 +45,46 @@ public class GetShardsWebScript extends AbstractAsieShardableWebScript { SolrShardHashSampleType sampleHashType = this.getOptionalQueryParameter(req, "sampleHashType", SolrShardHashSampleType.class); - Map shardSets = new TreeMap<>(); + Map shardSetsResponse = new TreeMap<>(); for (Entry>> floc : flocs.entrySet()) { - int maxShards = floc.getKey().getNumberOfShards(); ShardState anyShardNode = this.getAnyShardNode(floc.getValue()); - ShardSetInfo shardSet = new ShardSetInfo(floc.getKey(), anyShardNode); - shardSet.setShards(new TreeMap<>()); - - SolrShardHashTable sampleHashTable = sampleHashType == null ? null : this.createSampleHashTable(sampleHashType, maxShards); + ShardSet shardSet = ShardSet.from(floc.getKey(), anyShardNode); + ShardSetInfo shardSetResponse = ShardSetInfo.from(shardSet); + shardSetResponse.setShards(new TreeMap<>()); + + Short maxShards = shardSet.getShards(); + SolrShardHashTable sampleHashTable = null; + if (sampleHashType != null && maxShards != null) + sampleHashTable = this.createSampleHashTable(sampleHashType, maxShards); for (Entry> registeredShard : floc.getValue().entrySet()) { - ShardInfo shard = new ShardInfo(); - shard.setId(registeredShard.getKey().getInstance()); - shard.setNodes(new TreeMap<>()); + ShardInfo shardResponse = ShardInfo.from(registeredShard.getKey().getInstance()); + shardResponse.setNodes(new TreeMap<>()); for (ShardState registeredShardNode : registeredShard.getValue()) { - if (shard.getTxsCompleted() == null || shard.getTxsCompleted().longValue() < registeredShardNode.getLastIndexedTxId()) { - shard.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(registeredShardNode.getLastIndexedTxCommitTime()), ZoneOffset.UTC)); - shard.setTxsCompleted(registeredShardNode.getLastIndexedTxId()); + if (shardResponse.getTxsCompleted() == null || shardResponse.getTxsCompleted().longValue() < registeredShardNode.getLastIndexedTxId()) { + shardResponse.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(registeredShardNode.getLastIndexedTxCommitTime()), ZoneOffset.UTC)); + shardResponse.setTxsCompleted(registeredShardNode.getLastIndexedTxId()); } - NodeInfo node = new ShardNodeInfo(registeredShardNode); - shard.getNodes().put(node.getId(), node); + SolrHost node = SolrHost.from(registeredShardNode.getShardInstance()); + ShardInstanceState nodeShardState = ShardInstanceState.from(registeredShardNode); + NodeInfo nodeResponse = ShardNodeInfo.from(node, nodeShardState); + shardResponse.getNodes().put(nodeResponse.getId(), nodeResponse); } if (sampleHashTable != null) - this.addShardHashSamples(shardSet, shard, sampleHashTable); - shardSet.getShards().put(shard.getId(), shard); + this.addShardHashSamples(shardSetResponse, shardResponse, sampleHashTable); + shardSetResponse.getShards().put(shardResponse.getId(), shardResponse); } - shardSets.put(shardSet.getMethodSpec(), shardSet); + shardSetsResponse.put(shardSetResponse.getSpec(), shardSetResponse); } res.setContentType(MediaType.APPLICATION_JSON_VALUE); res.setContentEncoding("utf-8"); - this.getObjectMapper().writeValue(res.getWriter(), shardSets); + this.getObjectMapper().writeValue(res.getWriter(), shardSetsResponse); } private ShardState getAnyShardNode(Map> shards) { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeInfo.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeInfo.java index 6ac3d1d..fec997e 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeInfo.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeInfo.java @@ -3,12 +3,10 @@ package com.inteligr8.alfresco.asie.rest.model; import java.util.Map; import java.util.TreeMap; -import org.alfresco.repo.index.shard.ShardInstance; - import com.fasterxml.jackson.annotation.JsonProperty; -import com.inteligr8.alfresco.asie.model.Node; +import com.inteligr8.alfresco.asie.model.SolrHost; -public abstract class NodeInfo { +public abstract class NodeInfo implements ResponseInfo { @JsonProperty private String id; @@ -19,8 +17,8 @@ public abstract class NodeInfo { public NodeInfo() { } - public NodeInfo(ShardInstance nodeCache) { - this.setId(new Node(nodeCache).getId()); + protected NodeInfo(SolrHost node) { + this.id = node.getSpec(); } public String getId() { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/NodeParameterSet.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeParameterSet.java similarity index 92% rename from shared/src/main/java/com/inteligr8/alfresco/asie/model/NodeParameterSet.java rename to shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeParameterSet.java index 53453df..0e5899a 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/model/NodeParameterSet.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeParameterSet.java @@ -1,4 +1,4 @@ -package com.inteligr8.alfresco.asie.model; +package com.inteligr8.alfresco.asie.rest.model; import java.net.InetAddress; import java.net.UnknownHostException; diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeShardInfo.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeShardInfo.java index dad9cbb..a22bfe5 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeShardInfo.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeShardInfo.java @@ -2,25 +2,28 @@ package com.inteligr8.alfresco.asie.rest.model; import java.util.Map; -import org.alfresco.repo.index.shard.ShardInstance; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; +import com.inteligr8.alfresco.asie.model.SolrHost; @JsonInclude(Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) public class NodeShardInfo extends NodeInfo { + public static NodeShardInfo from(SolrHost node) { + return new NodeShardInfo(node); + } + @JsonProperty private Map shards; public NodeShardInfo() { } - public NodeShardInfo(ShardInstance nodeCache) { - super(nodeCache); + protected NodeShardInfo(SolrHost node) { + super(node); } } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/NodeShardParameterSet.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeShardParameterSet.java similarity index 80% rename from shared/src/main/java/com/inteligr8/alfresco/asie/model/NodeShardParameterSet.java rename to shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeShardParameterSet.java index 635f53c..ea5ee07 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/model/NodeShardParameterSet.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/NodeShardParameterSet.java @@ -1,4 +1,6 @@ -package com.inteligr8.alfresco.asie.model; +package com.inteligr8.alfresco.asie.rest.model; + +import com.inteligr8.alfresco.asie.model.ShardSet; public class NodeShardParameterSet extends NodeParameterSet { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/PropertyHashShardSetInfo.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/PropertyHashShardSetInfo.java index fdbf5b6..d856734 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/PropertyHashShardSetInfo.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/PropertyHashShardSetInfo.java @@ -2,24 +2,25 @@ package com.inteligr8.alfresco.asie.rest.model; import java.util.Map; -import org.alfresco.repo.index.shard.Floc; -import org.alfresco.repo.index.shard.ShardState; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.inteligr8.alfresco.asie.model.ShardSet; import com.fasterxml.jackson.annotation.JsonProperty; +import com.inteligr8.alfresco.asie.model.ShardSet; @JsonInclude(Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) -public class PropertyHashShardSetInfo { +public class PropertyHashShardSetInfo implements ResponseInfo { + + public static PropertyHashShardSetInfo from(ShardSet shardSet) { + return new PropertyHashShardSetInfo(shardSet); + } @JsonProperty - private String methodSpec; - - @JsonProperty - private int shardCount; + private String core; + + @JsonProperty + private String spec; @JsonProperty private Map shards; @@ -27,26 +28,25 @@ public class PropertyHashShardSetInfo { public PropertyHashShardSetInfo() { } - public PropertyHashShardSetInfo(Floc floc, ShardState anyShardNode) { - ShardSet shardSet = new ShardSet(floc, anyShardNode); - this.setMethodSpec(shardSet.toSpec()); - this.setShardCount(floc.getNumberOfShards()); + protected PropertyHashShardSetInfo(ShardSet shardSet) { + this.core = shardSet.getCore(); + this.spec = shardSet.toSpec(); + } + + public String getCore() { + return core; + } + + public void setCore(String core) { + this.core = core; } - public String getMethodSpec() { - return this.methodSpec; + public String getSpec() { + return this.spec; } - public void setMethodSpec(String methodSpec) { - this.methodSpec = methodSpec; - } - - public int getShardCount() { - return shardCount; - } - - public void setShardCount(int shardCount) { - this.shardCount = shardCount; + public void setSpec(String spec) { + this.spec = spec; } public Map getShards() { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/RequestParameterSet.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/RequestParameterSet.java new file mode 100644 index 0000000..556a696 --- /dev/null +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/RequestParameterSet.java @@ -0,0 +1,5 @@ +package com.inteligr8.alfresco.asie.rest.model; + +public interface RequestParameterSet { + +} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ResponseInfo.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ResponseInfo.java new file mode 100644 index 0000000..c742a3a --- /dev/null +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ResponseInfo.java @@ -0,0 +1,5 @@ +package com.inteligr8.alfresco.asie.rest.model; + +public interface ResponseInfo { + +} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardInfo.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardInfo.java index 3eab39e..ea141b5 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardInfo.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardInfo.java @@ -1,22 +1,27 @@ package com.inteligr8.alfresco.asie.rest.model; -import java.time.Instant; import java.time.OffsetDateTime; -import java.time.ZoneOffset; import java.util.Map; -import org.alfresco.repo.index.shard.ShardState; - import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonFormat.Shape; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; @JsonInclude(Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) -public class ShardInfo { +public class ShardInfo implements ResponseInfo { + + public static ShardInfo from(int shardId) { + return new ShardInfo(shardId, null); + } + + public static ShardInfo from(int shardId, ShardInstanceState nodeShardState) { + return new ShardInfo(shardId, nodeShardState); + } @JsonProperty private int id; @@ -40,10 +45,10 @@ public class ShardInfo { public ShardInfo() { } - public ShardInfo(ShardState shard) { - this.setId(shard.getShardInstance().getShard().getInstance()); - this.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(shard.getLastIndexedTxCommitTime()), ZoneOffset.UTC)); - this.setTxsCompleted(shard.getLastIndexedTxId()); + protected ShardInfo(int shardId, ShardInstanceState nodeShardState) { + this.id = shardId; + this.latestTx = nodeShardState == null ? null : nodeShardState.getLastIndexedTxTime(); + this.txsCompleted = nodeShardState == null ? null : nodeShardState.getLastIndexedTxId(); } public int getId() { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardNodeInfo.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardNodeInfo.java index 0fbf5a8..ef403fd 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardNodeInfo.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardNodeInfo.java @@ -1,10 +1,6 @@ package com.inteligr8.alfresco.asie.rest.model; -import java.time.Instant; import java.time.OffsetDateTime; -import java.time.ZoneOffset; - -import org.alfresco.repo.index.shard.ShardState; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat.Shape; @@ -12,11 +8,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; @JsonInclude(Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) public class ShardNodeInfo extends NodeInfo { + public static ShardNodeInfo from(SolrHost node, ShardInstanceState nodeShardState) { + return new ShardNodeInfo(node, nodeShardState); + } + @JsonProperty private Long txsCompleted; @@ -24,13 +26,16 @@ public class ShardNodeInfo extends NodeInfo { @JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX") private OffsetDateTime latestTx; + /** + * For Spring deserialization + */ public ShardNodeInfo() { } - public ShardNodeInfo(ShardState shard) { - super(shard.getShardInstance()); - this.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(shard.getLastIndexedTxCommitTime()), ZoneOffset.UTC)); - this.setTxsCompleted(shard.getLastIndexedTxId()); + protected ShardNodeInfo(SolrHost node, ShardInstanceState nodeShardState) { + super(node); + this.latestTx = nodeShardState.getLastIndexedTxTime(); + this.txsCompleted = nodeShardState.getLastIndexedTxId(); } public Long getTxsCompleted() { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardParameterSet.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardParameterSet.java similarity index 74% rename from shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardParameterSet.java rename to shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardParameterSet.java index 2036d75..b27e082 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/model/ShardParameterSet.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardParameterSet.java @@ -1,4 +1,6 @@ -package com.inteligr8.alfresco.asie.model; +package com.inteligr8.alfresco.asie.rest.model; + +import com.inteligr8.alfresco.asie.model.ShardSet; public class ShardParameterSet implements RequestParameterSet { diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardSetInfo.java b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardSetInfo.java index 88ea1a0..afbae9f 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardSetInfo.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/rest/model/ShardSetInfo.java @@ -4,24 +4,40 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; -import org.alfresco.repo.index.shard.Floc; -import org.alfresco.repo.index.shard.ShardState; +import org.alfresco.repo.index.shard.ShardMethodEnum; +import org.alfresco.service.cmr.repository.StoreRef; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.inteligr8.alfresco.asie.model.ShardSet; import com.fasterxml.jackson.annotation.JsonProperty; +import com.inteligr8.alfresco.asie.model.ShardSet; @JsonInclude(Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) -public class ShardSetInfo { +public class ShardSetInfo implements ResponseInfo { + + public static ShardSetInfo from(ShardSet shardSet) { + return new ShardSetInfo(shardSet); + } @JsonProperty - private String methodSpec; + private String spec; + + @JsonProperty + private ShardMethodEnum method; + + @JsonProperty + private boolean fulltextEnabled; + + @JsonProperty + private String template; @JsonProperty - private int shardCount; + private Set storeRefs; + + @JsonProperty + private Short shardCount; @JsonProperty private Map shards; @@ -32,25 +48,60 @@ public class ShardSetInfo { public ShardSetInfo() { } - public ShardSetInfo(Floc floc, ShardState anyShardNode) { - ShardSet shardSet = new ShardSet(floc, anyShardNode); - this.methodSpec = shardSet.toSpec(); - this.setShardCount(floc.getNumberOfShards()); + protected ShardSetInfo(ShardSet shardSet) { + this.spec = shardSet.toSpec(); + this.method = shardSet.getMethod(); + this.fulltextEnabled = shardSet.hasContent(); + this.template = shardSet.getTemplate(); + this.storeRefs = shardSet.getStoreRefs(); + this.shardCount = shardSet.getShards(); } - public String getMethodSpec() { - return this.methodSpec; + public String getSpec() { + return this.spec; } - public void setMethodSpec(String methodSpec) { - this.methodSpec = methodSpec; + public void setSpec(String spec) { + this.spec = spec; } - - public int getShardCount() { + + public ShardMethodEnum getMethod() { + return method; + } + + public void setMethod(ShardMethodEnum method) { + this.method = method; + } + + public boolean isFulltextEnabled() { + return fulltextEnabled; + } + + public void setFulltextEnabled(boolean fulltextEnabled) { + this.fulltextEnabled = fulltextEnabled; + } + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + + public Set getStoreRefs() { + return storeRefs; + } + + public void setStoreRefs(Set storeRefs) { + this.storeRefs = storeRefs; + } + + public Short getShardCount() { return shardCount; } - - public void setShardCount(int shardCount) { + + public void setShardCount(Short shardCount) { this.shardCount = shardCount; } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/service/ShardBackupService.java b/shared/src/main/java/com/inteligr8/alfresco/asie/service/ShardBackupService.java index 480fb0d..d9ac37c 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/service/ShardBackupService.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/service/ShardBackupService.java @@ -1,11 +1,7 @@ package com.inteligr8.alfresco.asie.service; import java.io.Serializable; -import java.util.Collection; -import org.alfresco.repo.index.shard.Shard; -import org.alfresco.repo.index.shard.ShardInstance; -import org.alfresco.repo.index.shard.ShardState; import org.alfresco.service.cmr.attributes.AttributeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,17 +11,14 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.inteligr8.alfresco.asie.Constants; -import com.inteligr8.alfresco.asie.model.Node; -import com.inteligr8.alfresco.asie.spi.ShardDiscoveryService; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; @Component public class ShardBackupService implements com.inteligr8.alfresco.asie.spi.ShardBackupService { private static final String ATTR_BACKUP_NODE = "backupNode"; private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Autowired - private ShardDiscoveryService sds; @Autowired @Qualifier(Constants.QUALIFIER_ASIE) @@ -34,21 +27,14 @@ public class ShardBackupService implements com.inteligr8.alfresco.asie.spi.Shard @Value("${inteligr8.asie.backup.persistTimeMinutes}") private int persistTimeMinutes; - public Node fetchNode(Collection shardNodes) { - if (shardNodes.isEmpty()) - return null; - - ShardState shardNode0 = shardNodes.iterator().next(); - ShardInstance node0Shard = shardNode0.getShardInstance(); - Shard shard = node0Shard.getShard(); - String shardKey = shard.getFloc().getShardMethod().name() + "~" + shard.getFloc().getNumberOfShards() + "~" + shard.getInstance(); + public SolrHost selectNode(ShardSet shardSet, int shardId, SolrHost node) { + String shardKey = shardSet.getCore() + "-" + shardId; PersistedNode backupNode = (PersistedNode) this.attributeService.getAttribute(Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey); this.logger.debug("Found backup node: {}", backupNode); if (backupNode == null || backupNode.isExpired()) { - ShardInstance backupShardInstance = this.sds.computeLeadShard(shardNodes); - backupNode = new PersistedNode(new Node(backupShardInstance)); + backupNode = new PersistedNode(node); this.attributeService.setAttribute(backupNode, Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey); } @@ -59,11 +45,8 @@ public class ShardBackupService implements com.inteligr8.alfresco.asie.spi.Shard this.attributeService.removeAttribute(Constants.ATTR_ASIE, ATTR_BACKUP_NODE); } - public void forget(ShardState shardNode) { - ShardInstance nodeShard = shardNode.getShardInstance(); - Shard shard = nodeShard.getShard(); - String shardKey = shard.getFloc().getShardMethod().name() + "~" + shard.getFloc().getNumberOfShards() + "~" + shard.getInstance(); - + public void forget(ShardSet shardSet, int shardId) { + String shardKey = shardSet.getCore() + "-" + shardId; this.attributeService.removeAttribute(Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey); } @@ -73,10 +56,10 @@ public class ShardBackupService implements com.inteligr8.alfresco.asie.spi.Shard private static final long serialVersionUID = 4105196543023419818L; - private final Node node; + private final SolrHost node; private long expireTimeMillis; - PersistedNode(Node node) { + PersistedNode(SolrHost node) { this.node = node; this.reset(); } @@ -89,7 +72,7 @@ public class ShardBackupService implements com.inteligr8.alfresco.asie.spi.Shard return this.expireTimeMillis < System.currentTimeMillis(); } - Node getNode() { + SolrHost getNode() { return this.node; } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/service/ShardDiscoveryService.java b/shared/src/main/java/com/inteligr8/alfresco/asie/service/ShardDiscoveryService.java deleted file mode 100644 index 9dfe2d5..0000000 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/service/ShardDiscoveryService.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.inteligr8.alfresco.asie.service; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.alfresco.repo.index.shard.Floc; -import org.alfresco.repo.index.shard.Shard; -import org.alfresco.repo.index.shard.ShardInstance; -import org.alfresco.repo.index.shard.ShardMethodEnum; -import org.alfresco.repo.index.shard.ShardRegistry; -import org.alfresco.repo.index.shard.ShardState; -import org.alfresco.util.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -import com.inteligr8.alfresco.asie.Constants; -import com.inteligr8.alfresco.asie.model.ShardSet; - -@Component -public class ShardDiscoveryService implements com.inteligr8.alfresco.asie.spi.ShardDiscoveryService { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Autowired - @Qualifier(Constants.QUALIFIER_ASIE) - private ShardRegistry shardRegistry; - - public ShardInstance computeLeadShard(Collection shardNodesCache) { - if (shardNodesCache.isEmpty()) - return null; - - long latestTime = 0L; - ShardInstance latestNode = null; - - for (ShardState shardNodeCache : shardNodesCache) { - if (latestTime < shardNodeCache.getLastIndexedTxCommitTime()) { - latestNode = shardNodeCache.getShardInstance(); - latestTime = shardNodeCache.getLastIndexedTxCommitTime(); - } - } - - return latestNode; - } - - public Set findByNode(String nodeHostname, int nodePort) { - Map>> flocs = this.shardRegistry.getFlocs(); - if (flocs.isEmpty()) - return Collections.emptySet(); - - Set shards = new HashSet<>(); - - for (Entry>> floc : flocs.entrySet()) { - for (Entry> flocShard : floc.getValue().entrySet()) { - for (ShardState shardState : flocShard.getValue()) { - ShardInstance shardInstance = shardState.getShardInstance(); - if (!nodeHostname.equalsIgnoreCase(shardInstance.getHostName())) { - InetAddress nodeAddress = this.resolve(nodeHostname); - if (nodeAddress == null) - continue; - - InetAddress shardInstanceAddress = this.resolve(shardInstance.getHostName()); - if (!nodeAddress.equals(shardInstanceAddress)) - continue; - } - - if (nodePort == shardInstance.getPort()) - shards.add(shardState); - } - } - } - - return shards; - } - - public Map> findByShardSet(ShardSet shardSet) { - Map>> flocs = this.shardRegistry.getFlocs(); - if (flocs.isEmpty()) - return Collections.emptyMap(); - this.logger.trace("Found {} shard sets", flocs.size()); - - for (Entry>> floc : flocs.entrySet()) { - if (!floc.getKey().getShardMethod().equals(shardSet.getMethod())) - continue; - - if (!shardSet.getConfig().isEmpty()) { - if (floc.getValue().isEmpty()) - continue; - Shard firstShard = floc.getValue().keySet().iterator().next(); - - Set firstShardStates = floc.getValue().get(firstShard); - if (firstShardStates == null || firstShardStates.isEmpty()) - continue; - ShardState firstShardState = firstShardStates.iterator().next(); - - Map firstShardProps = firstShardState.getPropertyBag(); - if (!shardSet.isConfigurationFor(firstShardProps)) - continue; - } - - return floc.getValue(); - } - - return Collections.emptyMap(); - } - - public Collection>>> findByShardMethod(ShardMethodEnum shardMethod) { - Map>> flocs = this.shardRegistry.getFlocs(); - if (flocs.isEmpty()) - return Collections.emptyList(); - this.logger.trace("Found {} shard sets", flocs.size()); - - List>>> filteredFlocs = new LinkedList<>(); - - for (Entry>> floc : flocs.entrySet()) { - if (!floc.getKey().getShardMethod().equals(shardMethod)) - continue; - filteredFlocs.add(new Pair<>(floc.getKey(), floc.getValue())); - } - - return filteredFlocs; - } - - public Set filterByShard(Map> shards, int shardId) { - if (shards == null) - return null; - - for (Entry> shard : shards.entrySet()) { - if (shard.getKey().getInstance() == shardId) - return shard.getValue(); - } - - return Collections.emptySet(); - } - - public Set findByShard(ShardSet shardSet, int shardId) { - Map> shards = this.findByShardSet(shardSet); - return this.filterByShard(shards, shardId); - } - - private InetAddress resolve(String hostname) { - try { - return InetAddress.getByName(hostname); - } catch (UnknownHostException uhe) { - return null; - } - } - -} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardBackupService.java b/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardBackupService.java index 7cfa9b8..d24836f 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardBackupService.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardBackupService.java @@ -1,17 +1,14 @@ package com.inteligr8.alfresco.asie.spi; -import java.util.Collection; - -import org.alfresco.repo.index.shard.ShardState; - -import com.inteligr8.alfresco.asie.model.Node; +import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; public interface ShardBackupService { - Node fetchNode(Collection shardNodes); + SolrHost selectNode(ShardSet shardSet, int shardId, SolrHost bestNode); void forget(); - void forget(ShardState shardNode); + void forget(ShardSet shardSet, int shardId); } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardDiscoveryService.java b/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardDiscoveryService.java index ba9e20a..e947a15 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardDiscoveryService.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardDiscoveryService.java @@ -1,72 +1,132 @@ package com.inteligr8.alfresco.asie.spi; +import java.time.OffsetDateTime; import java.util.Collection; +import java.util.Comparator; +import java.util.List; import java.util.Map; import java.util.Set; -import org.alfresco.repo.index.shard.Floc; -import org.alfresco.repo.index.shard.Shard; -import org.alfresco.repo.index.shard.ShardInstance; import org.alfresco.repo.index.shard.ShardMethodEnum; -import org.alfresco.repo.index.shard.ShardState; import org.alfresco.util.Pair; import com.inteligr8.alfresco.asie.model.ShardSet; +import com.inteligr8.alfresco.asie.model.SolrHost; +import com.inteligr8.alfresco.asie.model.ShardInstanceState; public interface ShardDiscoveryService { /** * Determine the lead shard in the specified node/shard snapshot metadata. * - * @param shardNodes A collection of snapshot metadata. + * @param shardNodeStates A collection of shard node/hosts and snapshot metadata. * @return A single node/shard holding the latest snapshot metadata. */ - ShardInstance computeLeadShard(Collection shardNodes); + default SolrHost computeLeadNode(Collection> shardNodeStates) { + if (shardNodeStates.isEmpty()) + return null; + + OffsetDateTime latestTime = OffsetDateTime.MIN; + SolrHost latestNode = null; + + for (Pair shardNodeState : shardNodeStates) { + if (latestTime.isBefore(shardNodeState.getSecond().getLastIndexedTxTime())) { + latestNode = shardNodeState.getFirst(); + latestTime = shardNodeState.getSecond().getLastIndexedTxTime(); + } + } + + return latestNode; + } + + /** + * Find the shard set by the specified core name. + * + * @param core A core name (without the shard identifier suffix). + * @return A shard set; null if not found. + */ + ShardSet findSetByCore(String core); + + /** + * Find the node with the specified hostname/port. + * + * @param nodeHostname The hostname of a ASIE node. + * @param nodePort The port of an ASIE node. + * @return A sharded node/host; null if not found. + */ + SolrHost findNode(String nodeHostname, int nodePort); /** * Find the latest snapshot of each shard on the specified node. * - * @param nodeHostname The hostname of a ASIE node. - * @param nodePort The port of an ASIE node. + * @param node A sharded node/host. * @return A set of the latest snapshot metadata of shards. */ - Set findByNode(String nodeHostname, int nodePort); + Map> findByNode(SolrHost node); /** - * Find the shards, their nodes, and the latest snapshot of each within the - * specified shard set. + * Find all shard sets that support the specified shard methods. + * + * @param shardMethods An array of shard methods. + * @return A set of shard sets. + */ + Set findSetsByShardMethod(ShardMethodEnum... shardMethods); + + /** + * Find the shard node/hosts for the specified shard set. * * @param shardSet A shard set. - * @return A map of shards to sets of the latest snapshot metadata of those shards and their nodes. + * @return A set of shard node/hosts. */ - Map> findByShardSet(ShardSet shardSet); + Set findNodes(ShardSet shardSet); /** - * Find the shards, their nodes, and the latest snapshot of each using the - * specified shard method. + * Find the shard node/hosts for the specified shard set and identifier. * - * @param shardMethod A shard method. - * @return A collection of maps of shards to sets of the latest snapshot metadata of those shards and their nodes. + * @param shardSet A shard set. + * @param shardId A shard identifier (e.g. 0). + * @return A set of shard node/hosts. */ - Collection>>> findByShardMethod(ShardMethodEnum shardMethod); + Set findNodesByShard(ShardSet shardSet, int shardId); + + Map> findLatestNodeStates(ShardSet shardSet); /** - * Filter the latest snapshot of each shard. - * - * @param shards A map of shards to sets of the latest snapshot metadata of those shards and their nodes. - * @param shardId A 0-based index of a shard. - * @return A set of the latest snapshot metadata of shards. + * Find the shard node/hosts and their states for the specified shard set + * and identifier. The list is left in an unknown order, but it is a list + * for easy use of a Comparator for sorting. + * + * @param shardSet A shard set. + * @param shardId A shard identifier (e.g. 0). + * @return A list of shard node/hosts and their latest state. */ - Set filterByShard(Map> shards, int shardId); + List> findNodeStatesByShard(ShardSet shardSet, int shardId); + + /** + * Find the shard identifiers for the specified shard set and node/host. + * + * @param shardSet A shard set. + * @param node A shard ndoe/host. + * @return A set of shard identifiers. + */ + Set findIdsByNode(ShardSet shardSet, SolrHost node); + + /** + * Find the shards and their states for the specified shard set and node/host. + * + * @param shardSet A shard set. + * @param node A shard ndoe/host. + * @return A map of shards and their states. + */ + Map findStatesByNode(ShardSet shardSet, SolrHost node); + + - /** - * Find the latest snapshot of each shard and their nodes within the - * specified shard set. - * - * @param shardSet A shard set. - * @param shardId A 0-based index of a shard. - * @return A set of the latest snapshot metadata of shards. - */ - Set findByShard(ShardSet shardSet, int shardId); + public class ShardedNodeShardStateComparator implements Comparator> { + @Override + public int compare(Pair p1, Pair p2) { + return - Long.compare(p1.getSecond().getLastIndexedTxId(), p2.getSecond().getLastIndexedTxId()); + } + } } diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardRegistry.java b/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardRegistry.java new file mode 100644 index 0000000..5dbc798 --- /dev/null +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardRegistry.java @@ -0,0 +1,9 @@ +package com.inteligr8.alfresco.asie.spi; + +import org.alfresco.repo.index.shard.ShardInstance; + +public interface ShardRegistry extends org.alfresco.repo.index.shard.ShardRegistry { + + void unregisterShardInstance(ShardInstance shardInstance); + +} diff --git a/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardStateService.java b/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardStateService.java index 5c82b90..f489556 100644 --- a/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardStateService.java +++ b/shared/src/main/java/com/inteligr8/alfresco/asie/spi/ShardStateService.java @@ -1,18 +1,13 @@ package com.inteligr8.alfresco.asie.spi; -import java.io.Serializable; - -import org.alfresco.service.cmr.attributes.AttributeService.AttributeQueryCallback; - public interface ShardStateService { /** * Clears the shard state. + * + * This allows the framework to provide an alternative implementation from + * what is provided by Alfresco Enterprise, which sometimes fails. */ void clear(); - - void remove(Serializable... keys); - - void iterate(AttributeQueryCallback callback); } diff --git a/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.delete.desc.xml b/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.delete.desc.xml index 37a7673..22b59f9 100644 --- a/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.delete.desc.xml +++ b/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.delete.desc.xml @@ -12,12 +12,10 @@
nodeEndpoint
A hostname or hostname:port for the ASIE node
-
shardSet
-
A shard method combined with its distinguishing properties; - methods: MOD_ACL_ID, ACL_ID, DB_ID, DB_ID_RANGE, DATE, PROPERTY, EXPLICIT_ID; - e.g. PROPERTY;key:cm:created;regex:^d{4} or DB_ID
+
shardCore
+
A core name (prefix) for the ASIE shard (e.g. alfresco)
shardId
-
A number starting at 1
+
A numeric shard ID for the ASIE shard (e.g. 0)

The following status codes should be expected:

@@ -31,7 +29,7 @@ ]]> - /inteligr8/asie/node/{nodeEndpoint}/shard/{shardSet}/{shardId} + /inteligr8/asie/node/{nodeEndpoint}/shard/{shardCore}/{shardId} admin diff --git a/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.get.desc.xml b/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.get.desc.xml new file mode 100644 index 0000000..0c2f08d --- /dev/null +++ b/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.get.desc.xml @@ -0,0 +1,41 @@ + + + + Retrieves ASIE Node Shard Status + Inteligr8 ASIE + Retrieves meta-data about all shards on a single ASIE node as registred with ACS.

+

The following query parameter is supported:

+
+
nodeEndpoint
+
A hostname or hostname:port for the ASIE node; dots are not allowed, you may use _ (underscore) instead
+
shardCore
+
A core name (prefix) for the ASIE shard (e.g. alfresco)
+
shardId
+
A numeric shard ID for the ASIE shard (e.g. 0)
+
+

The following status codes should be expected:

+
+
200
+
OK
+
400
+
The path parameters are invalid
+
404
+
The specified ASIE node/shard could not be found
+
+ ]]>
+ + + /inteligr8/asie/node/{nodeEndpoint}/shard/{shardCore}/{shardId} + + + admin + + + + false + false + + +
\ No newline at end of file diff --git a/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.post.desc.xml b/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.post.desc.xml index a3b3348..b502ed3 100644 --- a/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.post.desc.xml +++ b/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/nodeShard.post.desc.xml @@ -2,7 +2,7 @@ xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt"> - Adds ASIE Node to Registry + Adds ASIE Node/Shard to Registry Inteligr8 ASIE Loads an ASIE shard on a single ASIE node, which will eventually register with ACS.

diff --git a/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/shard.get.desc.xml b/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/shard.get.desc.xml index b595269..28f19b1 100644 --- a/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/shard.get.desc.xml +++ b/shared/src/main/resources/alfresco/extension/templates/webscripts/com/inteligr8/alfresco/asie/shard.get.desc.xml @@ -8,12 +8,10 @@

Retrieve meta-data about the specified ASIE shard registered with ACS.

The following path and query parameters are expected or supported:

-
shardSet
-
A shard method combined with its distinguishing properties; - methods: MOD_ACL_ID, ACL_ID, DB_ID, DB_ID_RANGE, DATE, PROPERTY, EXPLICIT_ID; - e.g. PROPERTY;key:cm:created;regex:^d{4} or DB_ID
+
shardCore
+
A core name (prefix) for the ASIE shard (e.g. alfresco)
shardId
-
A number starting at 1
+
A numeric shard ID for the ASIE shard (e.g. 0)
sampleHashType
A sample hash type; Sample hash types: PropertyYear, PropertyQuarter, PropertyMonth, PropertyWeek
@@ -58,7 +56,7 @@ ]]>
- /inteligr8/asie/shard/{shardSet}/{shardId}?includeSampleHashes={includeSampleHashes?} + /inteligr8/asie/shard/{shardCore}/{shardId}?includeSampleHashes={includeSampleHashes?} any diff --git a/solr-api/pom.xml b/solr-api/pom.xml index 26107ae..c484402 100644 --- a/solr-api/pom.xml +++ b/solr-api/pom.xml @@ -6,7 +6,7 @@ com.inteligr8.alfresco asie-platform-module-parent - 1.1-SNAPSHOT + 1.2-SNAPSHOT ../