Skip to content

Commit

Permalink
Merge pull request #76 from fullstorydev/patsonluk/SAI-4306-os-node-role
Browse files Browse the repository at this point in the history
SAI-4306 : Add overseer node role support
  • Loading branch information
patsonluk authored Jul 25, 2023
2 parents 9dfdd94 + c1518aa commit 635051c
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 24 deletions.
3 changes: 1 addition & 2 deletions src/main/java/StressMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,7 @@ private static Callable taskCallable(Workflow workflow, SolrCloud cloud, Map<Str

List<SolrNode> restartNodes;
if (type.restartAllNodes) {
restartNodes = new ArrayList<>(cloud.queryNodes);
restartNodes.addAll(cloud.nodes);
restartNodes = new ArrayList<>(cloud.nodes);
log.info("Restarting " + restartNodes.size() + " node(s)");
} else {
String nodeIndex = resolveString(resolveString(type.restartSolrNode, params), workflow.globalConstants);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static void runQueryBenchmarks(List<QueryBenchmark> queryBenchmarks, Stri
for (QueryBenchmark benchmark : queryBenchmarks) {
log.info("Query Benchmark name: " + benchmark.name);
results.get("query-benchmarks").put(benchmark.name, new ArrayList());
List<SolrNode> queryNodes = solrCloud.queryNodes.isEmpty() ? solrCloud.nodes : solrCloud.queryNodes;
List<? extends SolrNode> queryNodes = solrCloud.getNodesByRole(SolrCloud.NodeRole.COORDINATOR);
String baseUrl = queryNodes.get(benchmark.queryNode-1).getBaseUrl();
log.info("Query base URL " + baseUrl);
for (int threads = benchmark.minThreads; threads <= benchmark.maxThreads; threads++) {
Expand Down
86 changes: 65 additions & 21 deletions src/main/java/org/apache/solr/benchmarks/solrcloud/SolrCloud.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
Expand Down Expand Up @@ -64,9 +65,14 @@ public class SolrCloud {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

Zookeeper zookeeper;
public List<SolrNode> nodes = Collections.synchronizedList(new ArrayList());
public List<SolrNode> nodes = Collections.synchronizedList(new ArrayList()); //all nodes

public List<SolrNode> queryNodes = Collections.synchronizedList(new ArrayList());
public enum NodeRole {
DATA, COORDINATOR, OVERSEER
}

//Node list by role, though unlikely, a node can appear in multiple lists, ie a node with multiple roles
public Map<NodeRole, List<? extends SolrNode>> nodesByRole = new HashMap<>();

private Set<String> configsets = new HashSet<>();

Expand Down Expand Up @@ -185,32 +191,39 @@ public void init() throws Exception {
zookeeper = new GenericZookeeper(tokens[0], tokens.length > 1 ? Integer.parseInt(tokens[1]) : null, cluster.externalSolrConfig.zkAdminPort, cluster.externalSolrConfig.zkChroot);

try (CloudSolrClient client = new CloudSolrClient.Builder().withZkHost(cluster.externalSolrConfig.zkHost).withZkChroot(cluster.externalSolrConfig.zkChroot).build()) {
Collection<String> liveNodes = getExternalDataNodes(client);
for (String liveNode: liveNodes) {
for (String liveNode : client.getClusterStateProvider().getLiveNodes()) {
nodes.add(new ExternalSolrNode(
liveNode.split("_solr")[0].split(":")[0],
Integer.valueOf(liveNode.split("_solr")[0].split(":")[1]),
cluster.externalSolrConfig.sshUserName,
cluster.externalSolrConfig.restartScript));
}
try {
Collection<String> queryNodeList = getExternalQueryNodes(client);
for (String queryNode : queryNodeList) {
queryNodes.add(new ExternalSolrNode(
queryNode.split("_solr")[0].split(":")[0],
Integer.valueOf(queryNode.split("_solr")[0].split(":")[1]),
cluster.externalSolrConfig.sshUserName,
cluster.externalSolrConfig.restartScript));
}
} catch (KeeperException e) {
if (e.code() == KeeperException.Code.NONODE) {
log.info("No /live_query_nodes. Skipping query nodes.");
} else {
throw e;
}
List<SolrNode> dataNodes = getExternalDataNodes(client).stream().map(dataNode -> new ExternalSolrNode(
dataNode.split("_solr")[0].split(":")[0],
Integer.valueOf(dataNode.split("_solr")[0].split(":")[1]),
cluster.externalSolrConfig.sshUserName,
cluster.externalSolrConfig.restartScript)).collect(Collectors.toList());
if (!dataNodes.isEmpty()) {
nodesByRole.put(NodeRole.DATA, dataNodes);
}
List<SolrNode> queryNodes = getExternalQueryNodes(client).stream().map(queryNode -> new ExternalSolrNode(
queryNode.split("_solr")[0].split(":")[0],
Integer.valueOf(queryNode.split("_solr")[0].split(":")[1]),
cluster.externalSolrConfig.sshUserName,
cluster.externalSolrConfig.restartScript)).collect(Collectors.toList());
if (!queryNodes.isEmpty()) {
nodesByRole.put(NodeRole.COORDINATOR, queryNodes);
}
List<SolrNode> overseerNodes = getExternalPreferredOverseerNodes(client).stream().map(overseerNode -> new ExternalSolrNode(
overseerNode.split("_solr")[0].split(":")[0],
Integer.valueOf(overseerNode.split("_solr")[0].split(":")[1]),
cluster.externalSolrConfig.sshUserName,
cluster.externalSolrConfig.restartScript)).collect(Collectors.toList());
if (!queryNodes.isEmpty()) {
nodesByRole.put(NodeRole.OVERSEER, overseerNodes);
}
}
log.info("Cluster initialized with data nodes: " + nodes + ", query nodes: " + queryNodes + ", zkHost: " + zookeeper);
log.info("Cluster initialized with nodes: " + nodes + ", zkHost: " + zookeeper + ", nodes by role: " + nodesByRole);
}


Expand All @@ -230,7 +243,7 @@ private Collection<String> getExternalDataNodes(CloudSolrClient client) {
}
return client.getClusterStateProvider().getLiveNodes();
}
private Collection<String> getExternalQueryNodes(CloudSolrClient client) throws InterruptedException, KeeperException {
private Collection<String> getExternalQueryNodes(CloudSolrClient client) {
try {
if (client.getZkStateReader().getZkClient().exists("/node_roles/coordinator/on", true)) {
List<String> liveNodes = new ArrayList(client.getClusterStateProvider().getLiveNodes());
Expand All @@ -242,9 +255,29 @@ private Collection<String> getExternalQueryNodes(CloudSolrClient client) throws
} catch (Exception e) {
//ok, just use the /live_query_nodes
}
try {
return client.getZkStateReader().getZkClient().getChildren("/live_query_nodes", null, true);
} catch (Exception e) {
log.warn("Failed to look up query nodes. Skipping");
return Collections.emptyList();
}
}

private Collection<String> getExternalPreferredOverseerNodes(CloudSolrClient client) {
try {
if (client.getZkStateReader().getZkClient().exists("/node_roles/overseer/preferred", true)) {
List<String> liveNodes = new ArrayList(client.getClusterStateProvider().getLiveNodes());
liveNodes.retainAll(client.getZkStateReader().getZkClient().getChildren("/node_roles/overseer/preferred", null, true));
if (!liveNodes.isEmpty()) {
return liveNodes;
}
}
} catch (Exception e) {
log.warn("Failed to look up overseer nodes. Skipping");
}
return Collections.emptyList();
}


List<String> getSolrNodesFromTFState() throws JsonMappingException, JsonProcessingException, IOException {
List<String> out = new ArrayList<String>();
Expand Down Expand Up @@ -478,6 +511,17 @@ public SolrParams getParams() {

}

/**
* Gets the list of nodes by its NodeRole. If NodeRole is not supported, then return all nodes.
*
* Take note that currently only ExternalSolrNode has support for NodeRole.
* @param role
* @return
*/
public List<? extends SolrNode> getNodesByRole(NodeRole role) {
return nodesByRole.containsKey(role) ? nodesByRole.get(role) : nodes;
}

public String getProvisioningMethod() {
return cluster.provisioningMethod;
}
Expand Down

0 comments on commit 635051c

Please sign in to comment.