diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingSnitch.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingSnitch.java new file mode 100644 index 00000000000..fb489b1768e --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingSnitch.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cloud.autoscaling; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.solr.client.solrj.response.SimpleSolrResponse; +import org.apache.solr.cloud.rule.ServerSnitchContext; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.cloud.rule.ImplicitSnitch; +import org.apache.solr.common.cloud.rule.SnitchContext; +import org.apache.solr.common.params.CommonParams; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.util.StrUtils; +import org.apache.solr.common.util.Utils; + +//uses metrics API to get node information +public class AutoScalingSnitch extends ImplicitSnitch { + + + @Override + protected void getRemoteInfo(String solrNode, Set requestedTags, SnitchContext ctx) { + ServerSnitchContext snitchContext = (ServerSnitchContext) ctx; + List groups = new ArrayList<>(); + List prefixes = new ArrayList<>(); + if (requestedTags.contains(DISK)) { + groups.add("solr.node"); + prefixes.add("CONTAINER.fs.usableSpace"); + } + if (requestedTags.contains(CORES)) { + groups.add("solr.core"); + prefixes.add("CORE.coreName"); + } + if(groups.isEmpty() || prefixes.isEmpty()) return; + + ModifiableSolrParams params = new ModifiableSolrParams(); + params.add("group", StrUtils.join(groups, ',')); + params.add("prefix", StrUtils.join(prefixes,',')); + + try { + SimpleSolrResponse rsp = snitchContext.invoke(solrNode, CommonParams.METRICS_PATH, params); + Map m = rsp.nl.asMap(4); + if(requestedTags.contains(DISK)){ + Number n = (Number) Utils.getObjectByPath(m,true, "metrics/solr.node/CONTAINER.fs.usableSpace"); + if(n != null) ctx.getTags().put(DISK, n.longValue()); + } + if(requestedTags.contains(CORES)){ + int count = 0; + Map cores = (Map) m.get("metrics"); + for (Object o : cores.keySet()) { + if(o.toString().startsWith("solr.core.")) count++; + } + ctx.getTags().put(CORES, count); + } + + } catch (Exception e) { + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "", e); + } + + } +} diff --git a/solr/solrj/src/java/org/apache/solr/recipe/SolrClientClusterDataProvider.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ServerClusterDataProvider.java similarity index 69% rename from solr/solrj/src/java/org/apache/solr/recipe/SolrClientClusterDataProvider.java rename to solr/core/src/java/org/apache/solr/cloud/autoscaling/ServerClusterDataProvider.java index 295d0515a37..1267f8f9520 100644 --- a/solr/solrj/src/java/org/apache/solr/recipe/SolrClientClusterDataProvider.java +++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ServerClusterDataProvider.java @@ -15,29 +15,36 @@ * limitations under the License. */ -package org.apache.solr.recipe; +package org.apache.solr.cloud.autoscaling; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; -import org.apache.solr.client.solrj.impl.CloudSolrClient.ClusterStateProvider; +import org.apache.solr.cloud.rule.ServerSnitchContext; import org.apache.solr.common.cloud.ClusterState; import org.apache.solr.common.cloud.DocCollection; +import org.apache.solr.core.CoreContainer; import org.apache.solr.recipe.Policy.ClusterDataProvider; import org.apache.solr.recipe.Policy.ReplicaInfo; -public class SolrClientClusterDataProvider implements ClusterDataProvider { +public class ServerClusterDataProvider implements ClusterDataProvider { - private final ClusterStateProvider clusterStateProvider; + private final CoreContainer coreContainer; + private Set liveNodes; + private Map snitchSession = new HashMap<>(); private final Map>>> data = new HashMap<>(); - public SolrClientClusterDataProvider(ClusterStateProvider csp) { - this.clusterStateProvider = csp; - Map all = clusterStateProvider.getCollections(); + public ServerClusterDataProvider(CoreContainer coreContainer) { + this.coreContainer = coreContainer; + ClusterState clusterState = coreContainer.getZkController().getZkStateReader().getClusterState(); + this.liveNodes = clusterState.getLiveNodes(); + Map all = clusterState.getCollectionStates(); all.forEach((collName, ref) -> { DocCollection coll = ref.get(); if (coll == null) return; @@ -55,8 +62,10 @@ public class SolrClientClusterDataProvider implements ClusterDataProvider { @Override public Map getNodeValues(String node, Collection keys) { - //todo - return new HashMap<>(); + AutoScalingSnitch snitch = new AutoScalingSnitch(); + ServerSnitchContext ctx = new ServerSnitchContext(null, node, snitchSession, coreContainer); + snitch.getRemoteInfo(node, new HashSet<>(keys), ctx); + return ctx.getTags(); } @Override @@ -66,6 +75,6 @@ public class SolrClientClusterDataProvider implements ClusterDataProvider { @Override public Collection getNodes() { - return clusterStateProvider.liveNodes(); + return liveNodes; } } diff --git a/solr/core/src/java/org/apache/solr/cloud/rule/ServerSnitchContext.java b/solr/core/src/java/org/apache/solr/cloud/rule/ServerSnitchContext.java index 2d526fddbfd..446c80ffc5a 100644 --- a/solr/core/src/java/org/apache/solr/cloud/rule/ServerSnitchContext.java +++ b/solr/core/src/java/org/apache/solr/cloud/rule/ServerSnitchContext.java @@ -74,13 +74,12 @@ public class ServerSnitchContext extends SnitchContext { public void invokeRemote(String node, ModifiableSolrParams params, String klas, RemoteCallback callback) { if (callback == null) callback = this; - String url = coreContainer.getZkController().getZkStateReader().getBaseUrlForNodeName(node); params.add("class", klas); params.add(ACTION, INVOKE.toString()); //todo batch all requests to the same server try { - SimpleSolrResponse rsp = invoke(coreContainer.getUpdateShardHandler(), url, CommonParams.CORES_HANDLER_PATH, params); + SimpleSolrResponse rsp = invoke(node, CommonParams.CORES_HANDLER_PATH, params); Map returnedVal = (Map) rsp.getResponse().get(klas); if(exception == null){ // log this @@ -94,8 +93,10 @@ public class ServerSnitchContext extends SnitchContext { } } - public SimpleSolrResponse invoke(UpdateShardHandler shardHandler, final String url, String path, SolrParams params) + public SimpleSolrResponse invoke(String solrNode, String path, SolrParams params) throws IOException, SolrServerException { + String url = coreContainer.getZkController().getZkStateReader().getBaseUrlForNodeName(solrNode); + UpdateShardHandler shardHandler = coreContainer.getUpdateShardHandler(); GenericSolrRequest request = new GenericSolrRequest(SolrRequest.METHOD.GET, path, params); try (HttpSolrClient client = new HttpSolrClient.Builder(url).withHttpClient(shardHandler.getHttpClient()) .withResponseParser(new BinaryResponseParser()).build()) { diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java index 4172f65cc5a..b219facf2c8 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java @@ -60,7 +60,6 @@ import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.ToleratedUpdateError; import org.apache.solr.common.cloud.ClusterState; -import org.apache.solr.common.cloud.ClusterState.CollectionRef; import org.apache.solr.common.cloud.CollectionStatePredicate; import org.apache.solr.common.cloud.CollectionStateWatcher; import org.apache.solr.common.cloud.DocCollection; @@ -1446,7 +1445,7 @@ public class CloudSolrClient extends SolrClient { && !cacheEntry.shoulRetry()) return col; } - CollectionRef ref = getCollectionRef(collection); + ClusterState.CollectionRef ref = getCollectionRef(collection); if (ref == null) { //no such collection exists return null; @@ -1481,7 +1480,7 @@ public class CloudSolrClient extends SolrClient { } } - CollectionRef getCollectionRef(String collection) { + ClusterState.CollectionRef getCollectionRef(String collection) { return stateProvider.getState(collection); } @@ -1732,7 +1731,7 @@ public class CloudSolrClient extends SolrClient { public interface ClusterStateProvider extends Closeable { - CollectionRef getState(String collection); + ClusterState.CollectionRef getState(String collection); Set liveNodes(); @@ -1742,8 +1741,6 @@ public class CloudSolrClient extends SolrClient { Map getClusterProperties(); - Map getCollections(); - void connect(); } } diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ZkClientClusterStateProvider.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ZkClientClusterStateProvider.java index f0783e2236c..8ed1b5c45aa 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ZkClientClusterStateProvider.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ZkClientClusterStateProvider.java @@ -27,8 +27,6 @@ import java.util.Set; import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.Aliases; import org.apache.solr.common.cloud.ClusterState; -import org.apache.solr.common.cloud.ClusterState.CollectionRef; -import org.apache.solr.common.cloud.DocCollection; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.cloud.ZooKeeperException; import org.apache.zookeeper.KeeperException; @@ -54,7 +52,7 @@ public class ZkClientClusterStateProvider implements CloudSolrClient.ClusterStat } @Override - public CollectionRef getState(String collection) { + public ClusterState.CollectionRef getState(String collection) { return zkStateReader.getClusterState().getCollectionRef(collection); } @@ -183,11 +181,6 @@ public class ZkClientClusterStateProvider implements CloudSolrClient.ClusterStat return zkHostString; } - @Override - public Map getCollections() { - return zkStateReader.getClusterState().getCollectionStates(); - } - @Override public String toString() { return zkHost; diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/rule/ImplicitSnitch.java b/solr/solrj/src/java/org/apache/solr/common/cloud/rule/ImplicitSnitch.java index 1ae618d0ec8..3cae5726faa 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/rule/ImplicitSnitch.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/rule/ImplicitSnitch.java @@ -46,6 +46,7 @@ public class ImplicitSnitch extends Snitch { public static final String CORES = "cores"; public static final String DISK = "freedisk"; public static final String ROLE = "role"; + public static final String NODEROLE = "noderole"; public static final String SYSPROP = "sysprop."; public static final List IP_SNITCHES = Collections.unmodifiableList(Arrays.asList("ip_1", "ip_2", "ip_3", "ip_4")); public static final Set tags = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(NODE, PORT, HOST, CORES, DISK, ROLE, "ip_1", "ip_2", "ip_3", "ip_4"))); @@ -61,9 +62,14 @@ public class ImplicitSnitch extends Snitch { Matcher hostAndPortMatcher = hostAndPortPattern.matcher(solrNode); if (hostAndPortMatcher.find()) ctx.getTags().put(PORT, hostAndPortMatcher.group(2)); } - if (requestedTags.contains(ROLE)) fillRole(solrNode, ctx); + if (requestedTags.contains(ROLE) || requestedTags.contains(NODEROLE)) fillRole(solrNode, ctx); + addIpTags(solrNode, requestedTags, ctx); + getRemoteInfo(solrNode, requestedTags, ctx); + } + + protected void getRemoteInfo(String solrNode, Set requestedTags, SnitchContext ctx) { ModifiableSolrParams params = new ModifiableSolrParams(); if (requestedTags.contains(CORES)) params.add(CORES, "1"); if (requestedTags.contains(DISK)) params.add(DISK, "1"); diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/rule/SnitchContext.java b/solr/solrj/src/java/org/apache/solr/common/cloud/rule/SnitchContext.java index 3bb081b84f1..69a353ecc19 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/rule/SnitchContext.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/rule/SnitchContext.java @@ -44,10 +44,6 @@ public abstract class SnitchContext implements RemoteCallback { this.session = session; } - public SnitchInfo getSnitchInfo() { - return snitchInfo; - } - public Map getTags() { return tags; } diff --git a/solr/solrj/src/java/org/apache/solr/recipe/Policy.java b/solr/solrj/src/java/org/apache/solr/recipe/Policy.java index 032537819ab..0f6affa11da 100644 --- a/solr/solrj/src/java/org/apache/solr/recipe/Policy.java +++ b/solr/solrj/src/java/org/apache/solr/recipe/Policy.java @@ -201,11 +201,11 @@ public class Policy { } - static class ReplicaInfo implements MapWriter { + public static class ReplicaInfo implements MapWriter { final String name; Map variables; - ReplicaInfo(String name, Map vals) { + public ReplicaInfo(String name, Map vals) { this.name = name; this.variables = vals; } @@ -217,7 +217,7 @@ public class Policy { } - interface ClusterDataProvider { + public interface ClusterDataProvider { Map getNodeValues(String node, Collection keys); /** diff --git a/solr/solrj/src/java/org/apache/solr/recipe/package-info.java b/solr/solrj/src/java/org/apache/solr/recipe/package-info.java index d9730150856..7133e0f9a76 100644 --- a/solr/solrj/src/java/org/apache/solr/recipe/package-info.java +++ b/solr/solrj/src/java/org/apache/solr/recipe/package-info.java @@ -16,7 +16,7 @@ */ /** - * Common classes for recipe parsing filtering nodes & sorting + * Common classes for recipe parsing filtering nodes and sorting */ package org.apache.solr.recipe; \ No newline at end of file diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientCacheTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientCacheTest.java index 51b24f8e732..6adbaaedbcf 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientCacheTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientCacheTest.java @@ -149,11 +149,6 @@ public class CloudSolrClientCacheTest extends SolrTestCaseJ4 { @Override public void connect() { } - @Override - public Map getCollections() { - return Collections.emptyMap(); - } - @Override public void close() throws IOException {