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
../