You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2020/01/30 20:07:21 UTC
[lucene-solr] branch jira/solr-13579 updated: SOLR-13579: Fix the
v2 API paths. Fix some metrics / scope refactoring bugs.
This is an automated email from the ASF dual-hosted git repository.
ab pushed a commit to branch jira/solr-13579
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
The following commit(s) were added to refs/heads/jira/solr-13579 by this push:
new 159d5ac SOLR-13579: Fix the v2 API paths. Fix some metrics / scope refactoring bugs.
159d5ac is described below
commit 159d5ac164e031e7d1cabd858a781c079bbf184f
Author: Andrzej Bialecki <ab...@apache.org>
AuthorDate: Thu Jan 30 21:06:42 2020 +0100
SOLR-13579: Fix the v2 API paths. Fix some metrics / scope refactoring bugs.
---
.../java/org/apache/solr/core/CoreContainer.java | 2 +-
.../apache/solr/managed/ResourceManagerAPI.java | 46 +--
.../apache/solr/managed/ResourceManagerPool.java | 11 +
.../solr/managed/types/CacheManagerPool.java | 8 -
.../apache/solr/metrics/SolrCoreMetricManager.java | 2 +-
.../solr/handler/admin/MetricsHandlerTest.java | 2 +-
.../managed/TestResourceManagerIntegration.java | 328 +++++++++++++++++----
.../solr/client/solrj/impl/BaseHttpSolrClient.java | 4 +-
8 files changed, 309 insertions(+), 94 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index 6b7b0e8..55f13f2 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -629,7 +629,7 @@ public class CoreContainer {
metricManager = new SolrMetricManager(loader, cfg.getMetricsConfig());
String registryName = SolrMetricManager.getRegistryName(SolrInfoBean.Group.node);
- solrMetricsContext = new SolrMetricsContext(metricManager, registryName, "container", metricTag);
+ solrMetricsContext = new SolrMetricsContext(metricManager, registryName, metricTag);
coreContainerWorkExecutor = MetricUtils.instrumentedExecutorService(
coreContainerWorkExecutor, null,
diff --git a/solr/core/src/java/org/apache/solr/managed/ResourceManagerAPI.java b/solr/core/src/java/org/apache/solr/managed/ResourceManagerAPI.java
index 079368f..5f18c03 100644
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManagerAPI.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourceManagerAPI.java
@@ -291,7 +291,7 @@ public class ResourceManagerAPI implements SolrInfoBean {
// ============= helper methods ==============
- private List<ManagedComponent> getComponents(SolrQueryRequest req, SolrQueryResponse rsp, AtomicReference<ResourceManagerPool> poolRef) {
+ private List<ManagedComponent> getComponents(SolrQueryRequest req, SolrQueryResponse rsp, String componentPrefix, AtomicReference<ResourceManagerPool> poolRef) {
String poolName = req.getPathTemplateValues().get("poolName");
if (poolName == null || poolName.isBlank()) {
rsp.setException(new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Missing required pool name."));
@@ -303,7 +303,7 @@ public class ResourceManagerAPI implements SolrInfoBean {
return null;
}
poolRef.set(pool);
- String componentName = req.getPathTemplateValues().get("componentName");
+ String componentName = componentPrefix != null ? componentPrefix : req.getPathTemplateValues().get("componentName");
NamedList<Object> result = new SimpleOrderedMap<>();
// we support a prefix of component names because eg. searcher caches will have a quickly
// changing unique suffix
@@ -350,10 +350,10 @@ public class ResourceManagerAPI implements SolrInfoBean {
perPool.add("type", pool.getType());
perPool.add("size", pool.getComponents().size());
if (withLimits) {
- perPool.add("poolLimits", pool.getPoolLimits());
+ perPool.add("limits", pool.getPoolLimits());
}
if (withParams) {
- perPool.add("poolParams", pool.getPoolParams());
+ perPool.add("params", pool.getPoolParams());
}
if (withComponents) {
perPool.add("components", new TreeSet<>(pool.getComponents().keySet()));
@@ -361,7 +361,7 @@ public class ResourceManagerAPI implements SolrInfoBean {
if (withValues) {
try {
Map<String, Map<String, Object>> values = pool.getCurrentValues();
- perPool.add("totalValues", new TreeMap<>(pool.aggregateTotalValues(values)));
+ perPool.add("values", new TreeMap<>(pool.aggregateTotalValues(values)));
} catch (Exception e) {
log.warn("Error getting current values from pool " + name, e);
perPool.add("error", "Error getting current values: " + e.toString());
@@ -419,7 +419,7 @@ public class ResourceManagerAPI implements SolrInfoBean {
NamedList<Object> result = new SimpleOrderedMap<>();
rsp.add("result", result);
Set<String> toDelete = new TreeSet<>();
- if (payload.get() != null && !payload.get().isBlank()) {
+ if (payload != null && payload.get() != null && !payload.get().isBlank()) {
toDelete.add(payload.get());
}
if (req.getPathTemplateValues().get("poolName") != null) {
@@ -534,8 +534,8 @@ public class ResourceManagerAPI implements SolrInfoBean {
@EndPoint(
method = SolrRequest.METHOD.GET,
path = {
- "/cluster/resources/{poolName}/components",
- "/cluster/resources/{poolName}/components/{componentName}"
+ "/node/resources/{poolName}/components",
+ "/node/resources/{poolName}/components/{componentName}"
},
permission = PermissionNameProvider.Name.RESOURCE_READ_PERM
)
@@ -544,13 +544,14 @@ public class ResourceManagerAPI implements SolrInfoBean {
@Command()
public void list(SolrQueryRequest req, SolrQueryResponse rsp) {
AtomicReference<ResourceManagerPool> poolRef = new AtomicReference<>();
- List<ManagedComponent> components = getComponents(req, rsp, poolRef);
+ List<ManagedComponent> components = getComponents(req, rsp, null, poolRef);
if (components == null) {
return;
}
ResourceManagerPool pool = poolRef.get();
boolean withValues = req.getParams().getBool("values", false);
boolean withLimits = req.getParams().getBool("limits", false);
+ boolean withInitialLimits = req.getParams().getBool("initialLimits", false);
NamedList<Object> result = new SimpleOrderedMap<>();
rsp.add("result", result);
components.forEach(component -> {
@@ -559,15 +560,18 @@ public class ResourceManagerAPI implements SolrInfoBean {
perComponent.add("class", component.getClass().getName());
if (withLimits) {
try {
- perComponent.add("resourceLimits", new TreeMap<>(pool.getResourceLimits(component)));
+ perComponent.add("limits", new TreeMap<>(pool.getResourceLimits(component)));
} catch (Exception e) {
log.warn("Error getting resource limits of " + component.getManagedComponentId(), e);
result.add("error", "Error getting resource limits of " + component.getManagedComponentId() + ": " + e.toString());
}
}
+ if (withInitialLimits) {
+ perComponent.add("initialLimits", new TreeMap<>(pool.getInitialResourceLimits(component.getManagedComponentId().toString())));
+ }
if (withValues) {
try {
- perComponent.add("monitoredValues", new TreeMap<>(pool.getMonitoredValues(component)));
+ perComponent.add("values", new TreeMap<>(pool.getMonitoredValues(component)));
} catch (Exception e) {
log.warn("Error getting monitored values of " + component.getManagedComponentId() + "/" + pool.getName() + " : " + e.toString(), e);
perComponent.add("error", "Error getting monitored values of " + component.getManagedComponentId() + ": " + e.toString());
@@ -581,26 +585,28 @@ public class ResourceManagerAPI implements SolrInfoBean {
@EndPoint(
method = SolrRequest.METHOD.POST,
path = {
- "/cluster/resources/{poolName}/components",
- "/cluster/resources/{poolName}/components/{componentName}"
+ "/node/resources/{poolName}/components",
+ "/node/resources/{poolName}/components/{componentName}"
},
permission = PermissionNameProvider.Name.RESOURCE_WRITE_PERM
)
public class EditComponentAPI {
@Command(name = "setlimits")
- public void setLimits(SolrQueryRequest req, SolrQueryResponse rsp, PayloadObj<String> payload) {
+ public void setLimits(SolrQueryRequest req, SolrQueryResponse rsp, PayloadObj<Map<String, Object>> payload) {
if (!checkEnabled(payload)) return;
AtomicReference<ResourceManagerPool> poolRef = new AtomicReference<>();
- List<ManagedComponent> components = getComponents(req, rsp, poolRef);
+ List<ManagedComponent> components = getComponents(req, rsp, null, poolRef);
if (components == null) {
return;
}
NamedList<Object> result = new SimpleOrderedMap<>();
rsp.add("result", result);
ResourceManagerPool pool = poolRef.get();
- Map<String, Object> newLimits = (Map<String, Object>)Utils.fromJSONString(payload.get());
+ Map<String, Object> newLimits = payload.get();
for (ManagedComponent cmp : components) {
+ NamedList<Object> perComponent = new SimpleOrderedMap<>();
+ result.add(cmp.getManagedComponentId().toString(), perComponent);
try {
Map<String, Object> currentLimits = new HashMap<>(pool.getResourceLimits(cmp));
newLimits.forEach((k, v) -> {
@@ -612,14 +618,14 @@ public class ResourceManagerAPI implements SolrInfoBean {
});
try {
pool.setResourceLimits(cmp, newLimits, ChangeListener.Reason.USER);
- result.add("success", newLimits);
+ perComponent.addAll(newLimits);
} catch (Exception e) {
log.warn("Error setting resource limits of " + cmp.getManagedComponentId() + "/" + pool.getName() + " : " + e.toString(), e);
- result.add("error", "Error setting resource limits of " + cmp.getManagedComponentId() + ": " + e.toString());
+ perComponent.add("error", "Error setting resource limits of " + cmp.getManagedComponentId() + ": " + e.toString());
}
} catch (Exception e) {
log.warn("Error getting resource limits of " + cmp.getManagedComponentId() + "/" + pool.getName() + " : " + e.toString(), e);
- result.add("error", "Error getting resource limits of " + cmp.getManagedComponentId() + ": " + e.toString());
+ perComponent.add("error", "Error getting resource limits of " + cmp.getManagedComponentId() + ": " + e.toString());
}
}
}
@@ -632,7 +638,7 @@ public class ResourceManagerAPI implements SolrInfoBean {
NamedList<Object> result = new SimpleOrderedMap<>();
rsp.add("result", result);
AtomicReference<ResourceManagerPool> poolRef = new AtomicReference<>();
- List<ManagedComponent> components = getComponents(req, rsp, poolRef);
+ List<ManagedComponent> components = getComponents(req, rsp, payload.get(), poolRef);
if (components == null) {
return;
}
diff --git a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPool.java b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPool.java
index dc3ac6a..cdcf304 100644
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPool.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPool.java
@@ -55,6 +55,7 @@ public abstract class ResourceManagerPool<T extends ManagedComponent> implements
protected final String type;
protected final Map<String, Object> poolLimits = new ConcurrentHashMap<>();
protected final Map<String, T> components = new ConcurrentHashMap<>();
+ protected final Map<String, Map<String, Object>> initialComponentLimits = new ConcurrentHashMap<>();
protected final ResourceManager resourceManager;
protected final Class<? extends ManagedComponent> componentClass;
protected final Map<String, Object> poolParams = new ConcurrentHashMap<>();
@@ -141,13 +142,23 @@ public abstract class ResourceManagerPool<T extends ManagedComponent> implements
if (existing != null) {
throw new IllegalArgumentException("Component '" + managedComponent.getManagedComponentId() + "' already exists in pool '" + name + "' !");
}
+ try {
+ initialComponentLimits.put(managedComponent.getManagedComponentId().toString(), getResourceLimits(managedComponent));
+ } catch (Exception e) {
+ log.warn("Could not retrieve initial component limits for {} / {}: {}", managedComponent.getManagedComponentId(), getName(), e);
+ }
}
/** Remove named component from this pool. */
public boolean unregisterComponent(String componentId) {
+ initialComponentLimits.remove(componentId);
return components.remove(componentId) != null;
}
+ public Map<String, Object> getInitialResourceLimits(String componentId) {
+ return initialComponentLimits.getOrDefault(componentId, Collections.emptyMap());
+ }
+
/**
* Check whether a named component is registered in this pool.
* @param componentId component id
diff --git a/solr/core/src/java/org/apache/solr/managed/types/CacheManagerPool.java b/solr/core/src/java/org/apache/solr/managed/types/CacheManagerPool.java
index e070488..9c76d71 100644
--- a/solr/core/src/java/org/apache/solr/managed/types/CacheManagerPool.java
+++ b/solr/core/src/java/org/apache/solr/managed/types/CacheManagerPool.java
@@ -124,7 +124,6 @@ public class CacheManagerPool extends ResourceManagerPool<SolrCache> {
protected boolean optimize_expand = true;
protected Map<String, Long> lookups = new HashMap<>();
protected Map<String, Long> hits = new HashMap<>();
- protected Map<String, Map<String, Object>> initialComponentLimits = new HashMap<>();
protected int reportExceededCounter = 0;
protected int reportExceededThreshold = DEFAULT_REPORT_EXCEEDED_THRESHOLD;
@@ -175,16 +174,9 @@ public class CacheManagerPool extends ResourceManagerPool<SolrCache> {
}
@Override
- public void registerComponent(SolrCache component) {
- super.registerComponent(component);
- initialComponentLimits.put(component.getManagedComponentId().toString(), getResourceLimits(component));
- }
-
- @Override
public boolean unregisterComponent(String componentId) {
lookups.remove(componentId);
hits.remove(componentId);
- initialComponentLimits.remove(componentId);
return super.unregisterComponent(componentId);
}
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java b/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java
index 7fb0944..39c672a 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java
@@ -53,7 +53,7 @@ public class SolrCoreMetricManager implements Closeable {
initCloudMode();
metricManager = core.getCoreContainer().getMetricManager();
String registryName = createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName());
- solrMetricsContext = new SolrMetricsContext(metricManager, registryName, "SolrCore", core.getMetricTag());
+ solrMetricsContext = new SolrMetricsContext(metricManager, registryName, core.getMetricTag());
leaderRegistryName = createLeaderRegistryName(cloudMode, collectionName, shardName);
}
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
index 18b4efe..53db494 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
@@ -444,7 +444,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
super.initializeMetrics(parentContext, scope);
MetricsMap metrics = new MetricsMap((detailed, map) -> map.putAll(gaugevals));
solrMetricsContext.gauge(
- metrics, true, "dumphandlergauge", getCategory().toString(), scope);
+ metrics, true, "dumphandlergauge", getCategory().toString());
}
diff --git a/solr/core/src/test/org/apache/solr/managed/TestResourceManagerIntegration.java b/solr/core/src/test/org/apache/solr/managed/TestResourceManagerIntegration.java
index 730d1b4..cfdd465 100644
--- a/solr/core/src/test/org/apache/solr/managed/TestResourceManagerIntegration.java
+++ b/solr/core/src/test/org/apache/solr/managed/TestResourceManagerIntegration.java
@@ -1,8 +1,9 @@
package org.apache.solr.managed;
-import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -19,18 +20,15 @@ import org.apache.solr.cloud.CloudUtil;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.Utils;
+import org.apache.solr.search.CaffeineCache;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
*
*/
public class TestResourceManagerIntegration extends SolrCloudTestCase {
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static ResourceManager resourceManager;
private static CloudSolrClient solrClient;
@@ -66,69 +64,275 @@ public class TestResourceManagerIntegration extends SolrCloudTestCase {
public void testPoolAPI() throws Exception {
// READ API
-
+ Set<String> expectedPools = resourceManager.getDefaultPoolConfigs().keySet();
// read all
- V2Request req = new V2Request.Builder("/cluster/resources")
- .forceV2(true)
- .withMethod(SolrRequest.METHOD.GET)
- .withParams(params("values", "true", "components", "true", "limits", "true", "params", "true"))
- .build();
+ {
+ V2Request req = new V2Request.Builder("/cluster/resources")
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.GET)
+ .withParams(params("values", "true", "components", "true", "limits", "true", "params", "true"))
+ .build();
- V2Response rsp = req.process(cluster.getSolrClient());
- Set<String> expectedPools = resourceManager.getDefaultPoolConfigs().keySet();
- NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
- assertEquals(rsp.toString(), expectedPools.size(), result.size());
- expectedPools.forEach(p -> {
- assertNotNull("default pool " + p + " is missing!", result.get(p));
- NamedList<Object> pool = (NamedList<Object>) result.get(p);
- assertTrue(pool.toString(), pool.get("type") != null && pool.get("type").toString().equals("cache"));
- assertTrue(pool.toString(), pool.get("size") != null && ((Number)pool.get("size")).intValue() > 0);
- assertTrue(pool.toString(), pool.get("poolLimits") != null);
- assertTrue(pool.toString(), pool.get("poolParams") != null);
- assertTrue(pool.toString(), pool.get("components") != null);
- assertTrue(pool.toString(), pool.get("totalValues") != null);
- });
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals(rsp.toString(), expectedPools.size(), result.size());
+ expectedPools.forEach(p -> {
+ assertNotNull("default pool " + p + " is missing!", result.get(p));
+ NamedList<Object> pool = (NamedList<Object>) result.get(p);
+ assertTrue(pool.toString(), pool.get("type") != null && pool.get("type").toString().equals("cache"));
+ assertTrue(pool.toString(), pool.get("size") != null && ((Number)pool.get("size")).intValue() > 0);
+ assertTrue(pool.toString(), pool.get("limits") != null);
+ assertTrue(pool.toString(), pool.get("params") != null);
+ assertTrue(pool.toString(), pool.get("components") != null);
+ assertTrue(pool.toString(), pool.get("values") != null);
+ });
+ }
// read one
- String poolName = expectedPools.iterator().next();
-
- req = new V2Request.Builder("/cluster/resources/" + poolName)
- .forceV2(true)
- .withMethod(SolrRequest.METHOD.GET)
- .build();
- rsp = req.process(cluster.getSolrClient());
- NamedList<Object> result1 = (NamedList<Object>)rsp.getResponse().get("result");
- assertEquals(rsp.toString(), 1, result1.size());
- assertNotNull(rsp.toString(), result1.get(poolName));
-
- // create one
- ResourcePoolConfig config = new ResourcePoolConfig();
- config.name = "foo";
- config.type = "cache";
- config.poolLimits.put("foo", "bar");
- config.poolLimits.put("baz", 10);
- config.poolParams.put("foo", "bar");
-
- req = new V2Request.Builder("/cluster/resources")
- .forceV2(true)
- .withMethod(SolrRequest.METHOD.POST)
- .withPayload(Collections.singletonMap("create", config))
- .build();
- rsp = req.process(cluster.getSolrClient());
- NamedList<Object> result2 = (NamedList<Object>)rsp.getResponse().get("result");
- assertNotNull(result2.toString(), result2.get("success"));
+ {
+ String poolName = expectedPools.iterator().next();
+
+ V2Request req = new V2Request.Builder("/cluster/resources/" + poolName)
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.GET)
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals(rsp.toString(), 1, result.size());
+ assertNotNull(rsp.toString(), result.get(poolName));
+ }
+
+ // WRITE API
+
+ // create
+ {
+ ResourcePoolConfig config = new ResourcePoolConfig();
+ config.name = "testPool";
+ config.type = "cache";
+ config.poolLimits.put("foo", "bar");
+ config.poolLimits.put("baz", 10);
+ config.poolParams.put("foo", "bar");
+
+ V2Request req = new V2Request.Builder("/cluster/resources")
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("create", config))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertNotNull(result.toString(), result.get("success"));
+
+ config.name = "testPool2";
+ req = new V2Request.Builder("/cluster/resources")
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("create", config))
+ .build();
+ rsp = req.process(cluster.getSolrClient());
+ result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertNotNull(result.toString(), result.get("success"));
+ }
// set params
- Map<String, Object> map = new HashMap<>();
- map.put("foo", null);
- map.put("bar", "xyz");
- req = new V2Request.Builder("/cluster/resources/foo")
- .forceV2(true)
- .withMethod(SolrRequest.METHOD.POST)
- .withPayload(Collections.singletonMap("setparams", map))
- .build();
- rsp = req.process(cluster.getSolrClient());
- NamedList<Object> result3 = (NamedList<Object>)rsp.getResponse().get("result");
+ {
+ Map<String, Object> map = new HashMap<>();
+ map.put("foo", null);
+ map.put("bar", "xyz");
+ map.put("baz", 10);
+ V2Request req = new V2Request.Builder("/cluster/resources/testPool")
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("setparams", map))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertNotNull("missing pool testPool params: " + result, result.get("testPool"));
+ Map<String, Object> newParams = (Map<String, Object>) result.get("testPool");
+ assertNull("foo param should be removed: " + newParams, newParams.get("foo"));
+ assertEquals(newParams.toString(), "xyz", newParams.get("bar"));
+ assertTrue("baz should be a number: " + newParams, newParams.get("baz") instanceof Number);
+ assertEquals(newParams.toString(), 10, ((Number)newParams.get("baz")).intValue());
+ }
+
+ // set limits
+ {
+ Map<String, Object> map = new HashMap<>();
+ map.put("foo", null);
+ map.put("maxSize", -10);
+ map.put("maxRamMB", 100);
+ map.put("baz", 10);
+ V2Request req = new V2Request.Builder("/cluster/resources/testPool")
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("setlimits", map))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertNotNull("missing pool testPool limits: " + result, result.get("testPool"));
+ Map<String, Object> newLimits = (Map<String, Object>) result.get("testPool");
+ assertNull("foo limit should be removed: " + newLimits, newLimits.get("foo"));
+ assertEquals(newLimits.toString(), "xyz", newLimits.get("bar"));
+ assertTrue("baz should be a number: " + newLimits, newLimits.get("baz") instanceof Number);
+ assertEquals(newLimits.toString(), 10, ((Number)newLimits.get("baz")).intValue());
+ assertTrue("maxSize should be a number: " + newLimits, newLimits.get("maxSize") instanceof Number);
+ assertEquals(newLimits.toString(), -10, ((Number)newLimits.get("maxSize")).intValue());
+ assertTrue("maxRamMB should be a number: " + newLimits, newLimits.get("maxRamMB") instanceof Number);
+ assertEquals(newLimits.toString(), 100, ((Number)newLimits.get("maxRamMB")).intValue());
+ }
+
+ // delete
+
+ // delete by path
+ {
+ V2Request req = new V2Request.Builder("/cluster/resources/testPool")
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("delete", null))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals(result.toString(), "success", result.get("testPool"));
+ }
+ // delete by payload
+ {
+ V2Request req = new V2Request.Builder("/cluster/resources")
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("delete", "testPool2"))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals(result.toString(), "success", result.get("testPool2"));
+ }
+ // attempt deleting a predefined pool
+ {
+ String poolName = expectedPools.iterator().next();
+ V2Request req = new V2Request.Builder("/cluster/resources")
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("delete", poolName))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals(result.toString(), "ignored - cannot delete default pool", result.get(poolName));
+ }
+ }
+
+ @Test
+ public void testComponentAPI() throws Exception {
+
+ // READ API
+ Set<String> expectedPools = resourceManager.getDefaultPoolConfigs().keySet();
+ List<String> randomPools = new ArrayList<>(expectedPools);
+ Collections.shuffle(randomPools, random());
+ String componentsPath = "/node/resources/" + randomPools.get(0) + "/components";
+ List<String> componentIds = new ArrayList<>();
+ // list
+ {
+ V2Request req = new V2Request.Builder(componentsPath)
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.GET)
+ .withParams(params("values", "true", "limits", "true", "initialLimits", "true"))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ // 4 replicas, 2 of each shard
+ assertEquals(result.toString(), 4, result.size());
+ result.asMap(10).forEach((cmp, obj) -> {
+ // capture component id-s
+ componentIds.add(String.valueOf(cmp));
+
+ Map<String, Object> status = (Map<String, Object>) obj;
+ assertEquals(status.toString(), CaffeineCache.class.getName(), status.get("class"));
+ assertNotNull("limits are missing: " + status.toString(), status.get("limits"));
+ Map<String, Object> limits = (Map<String, Object>) status.get("limits");
+ assertNotNull("maxSize limit is missing: " + status.toString(), limits.get("maxSize"));
+ assertNotNull("maxRamMB limit is missing: " + status.toString(), limits.get("maxRamMB"));
+ assertNotNull("initialLimits are missing: " + status.toString(), status.get("initialLimits"));
+ assertNotNull("values are missing: " + status.toString(), status.get("values"));
+ });
+ }
+
+ Collections.shuffle(componentIds, random());
+
+ // WRITE API
+
+ // setlimits for all
+ {
+ Map<String, Object> limits = new HashMap<>();
+ limits.put("maxSize", 11);
+ limits.put("maxRamMB", 111);
+ V2Request req = new V2Request.Builder(componentsPath)
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("setlimits", limits))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals("exactly 4 components should be present: " + result.toString(), 4, result.size());
+ result.asMap(10).forEach((cmp, obj) -> {
+ Map<String, Object> newLimits = (Map<String, Object>)obj;
+ assertEquals(newLimits.toString(), 11, ((Number) newLimits.get("maxSize")).intValue());
+ assertEquals(newLimits.toString(), 111, ((Number) newLimits.get("maxRamMB")).intValue());
+ });
+ }
+
+ String componentId = componentIds.get(0);
+ String prefix = componentId.substring(0, componentId.indexOf("replica"));
+
+ // setlimits for prefix
+ {
+ Map<String, Object> limits = new HashMap<>();
+ limits.put("maxSize", 10);
+ limits.put("maxRamMB", 110);
+ V2Request req = new V2Request.Builder(componentsPath + "/" + prefix)
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("setlimits", limits))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals("exactly 2 components should be present: " + result.toString(), 2, result.size());
+ result.asMap(10).forEach((cmp, obj) -> {
+ Map<String, Object> newLimits = (Map<String, Object>)obj;
+ assertEquals(newLimits.toString(), 10, ((Number) newLimits.get("maxSize")).intValue());
+ assertEquals(newLimits.toString(), 110, ((Number) newLimits.get("maxRamMB")).intValue());
+ });
+ }
+
+ // delete by prefix
+ List<String> removed = new ArrayList<>();
+ {
+ V2Request req = new V2Request.Builder(componentsPath + "/" + prefix)
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("delete", null))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals("exactly 2 components should be removed: " + result.toString(), 2, result.size());
+ result.asMap(10).forEach((cmp, obj) -> {
+ assertEquals(result.toString(), "removed", obj);
+ removed.add(String.valueOf(cmp));
+ });
+ }
+
+ // delete by id
+ componentIds.removeAll(removed);
+ componentId = componentIds.get(0);
+ {
+ V2Request req = new V2Request.Builder(componentsPath)
+ .forceV2(true)
+ .withMethod(SolrRequest.METHOD.POST)
+ .withPayload(Collections.singletonMap("delete", componentId))
+ .build();
+ V2Response rsp = req.process(cluster.getSolrClient());
+ NamedList<Object> result = (NamedList<Object>)rsp.getResponse().get("result");
+ assertEquals("exactly 1 component should be removed: " + result.toString(), 1, result.size());
+ result.asMap(10).forEach((cmp, obj) -> {
+ assertEquals(result.toString(), "removed", obj);
+ });
+ }
}
@AfterClass
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpSolrClient.java
index dceb13c..2db6442 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpSolrClient.java
@@ -52,7 +52,7 @@ public abstract class BaseHttpSolrClient extends SolrClient {
private NamedList meta;
public RemoteExecutionException(String remoteHost, int code, String msg, NamedList meta) {
- super(remoteHost, code, msg, null);
+ super(remoteHost, code, msg + (meta != null ? ": " + meta : ""), null);
this.meta = meta;
}
@@ -71,6 +71,8 @@ public abstract class BaseHttpSolrClient extends SolrClient {
}
+
+
public NamedList getMetaData() {
return meta;