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 2019/12/18 16:39:10 UTC
[lucene-solr] 32/36: SOLR-13579: Simplify the API, add more tests.
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
commit 5860e3dc96fee08b453fc1db76edc836d1a41631
Author: Andrzej Bialecki <ab...@apache.org>
AuthorDate: Tue Nov 26 15:10:45 2019 +0100
SOLR-13579: Simplify the API, add more tests.
---
.../solr/handler/admin/ResourceManagerHandler.java | 16 +-
.../{ManagedComponent.java => ChangeListener.java} | 26 ++-
.../solr/managed/DefaultResourceManager.java | 32 ++--
.../solr/managed/DefaultResourceManagerPool.java | 168 ------------------
...java => DefaultResourceManagerPoolFactory.java} | 53 +++---
.../org/apache/solr/managed/ManagedComponent.java | 6 +-
.../apache/solr/managed/ManagedComponentId.java | 25 +--
.../apache/solr/managed/NoOpResourceManager.java | 113 +++---------
.../org/apache/solr/managed/ResourceManager.java | 16 +-
.../apache/solr/managed/ResourceManagerPlugin.java | 93 ----------
.../apache/solr/managed/ResourceManagerPool.java | 190 +++++++++++++++++++--
...actory.java => ResourceManagerPoolFactory.java} | 15 +-
.../{PoolContext.java => ResourcePoolContext.java} | 2 +-
...anagedContext.java => SolrResourceContext.java} | 4 +-
...cheManagerPlugin.java => CacheManagerPool.java} | 112 ++++++------
.../apache/solr/managed/types/package-info.java | 2 +-
.../java/org/apache/solr/search/CaffeineCache.java | 21 ++-
.../src/java/org/apache/solr/search/SolrCache.java | 2 +
.../org/apache/solr/search/SolrCacheHolder.java | 6 +-
...nagerPool.java => TestResourceManagerPool.java} | 83 +++------
...lugin.java => TestCacheManagerPluginCloud.java} | 2 +-
.../solr/managed/types/TestCacheManagerPool.java | 117 +++++++++++++
22 files changed, 507 insertions(+), 597 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ResourceManagerHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/ResourceManagerHandler.java
index 854da43..dd587ca 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/ResourceManagerHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ResourceManagerHandler.java
@@ -151,7 +151,7 @@ public class ResourceManagerHandler extends RequestHandlerBase implements Permis
result.add("resources", pool.getComponents().keySet());
try {
Map<String, Map<String, Object>> values = pool.getCurrentValues();
- result.add("totalValues", pool.getResourceManagerPlugin().aggregateTotalValues(values));
+ result.add("totalValues", pool.aggregateTotalValues(values));
} catch (Exception e) {
log.warn("Error getting current values from pool " + name, e);
result.add("error", "Error getting current values: " + e.toString());
@@ -225,7 +225,7 @@ public class ResourceManagerHandler extends RequestHandlerBase implements Permis
if (poolName == null || poolName.isBlank()) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Resource operation requires '" + POOL_PARAM + "' parameter.");
}
- ResourceManagerPool pool = resourceManager.getPool(poolName);
+ ResourceManagerPool<ManagedComponent> pool = resourceManager.getPool(poolName);
if (pool == null) {
throw new SolrException(SolrException.ErrorCode.NOT_FOUND, "Pool '" + poolName + "' not found.");
}
@@ -241,7 +241,7 @@ public class ResourceManagerHandler extends RequestHandlerBase implements Permis
result.add(n, perRes);
perRes.add("class", component.getClass().getName());
try {
- perRes.add("resourceLimits", pool.getResourceManagerPlugin().getResourceLimits(component));
+ perRes.add("resourceLimits", pool.getResourceLimits(component));
} catch (Exception e) {
log.warn("Error getting resourceLimits of " + component.getManagedComponentId(), e);
result.add("error", "Error getting resource limits of " + resName + ": " + e.toString());
@@ -255,13 +255,13 @@ public class ResourceManagerHandler extends RequestHandlerBase implements Permis
}
result.add("class", component.getClass().getName());
try {
- result.add("resourceLimits", pool.getResourceManagerPlugin().getResourceLimits(component));
+ result.add("resourceLimits", pool.getResourceLimits(component));
} catch (Exception e) {
log.warn("Error getting resource limits of " + resName + "/" + poolName + " : " + e.toString(), e);
result.add("error", "Error getting resource limits of " + resName + ": " + e.toString());
}
try {
- result.add("monitoredValues", pool.getResourceManagerPlugin().getMonitoredValues(component));
+ result.add("monitoredValues", pool.getMonitoredValues(component));
} catch (Exception e) {
log.warn("Error getting monitored values of " + resName + "/" + poolName + " : " + e.toString(), e);
result.add("error", "Error getting monitored values of " + resName + ": " + e.toString());
@@ -273,7 +273,7 @@ public class ResourceManagerHandler extends RequestHandlerBase implements Permis
throw new SolrException(SolrException.ErrorCode.NOT_FOUND, "Component '" + resName + " not found in pool '" + poolName + "'.");
}
try {
- result.add("resourceLimits", pool.getResourceManagerPlugin().getResourceLimits(managedComponent1));
+ result.add("resourceLimits", pool.getResourceLimits(managedComponent1));
} catch (Exception e) {
log.warn("Error getting resource limits of " + resName + "/" + poolName + " : " + e.toString(), e);
result.add("error", "Error getting resource limits of " + resName + ": " + e.toString());
@@ -285,7 +285,7 @@ public class ResourceManagerHandler extends RequestHandlerBase implements Permis
throw new SolrException(SolrException.ErrorCode.NOT_FOUND, "Resource '" + resName + " not found in pool '" + poolName + "'.");
}
try {
- Map<String, Object> currentLimits = new HashMap<>(pool.getResourceManagerPlugin().getResourceLimits(managedComponent2));
+ Map<String, Object> currentLimits = new HashMap<>(pool.getResourceLimits(managedComponent2));
Map<String, Object> newLimits = getMap(params, LIMIT_PREFIX_PARAM);
newLimits.forEach((k, v) -> {
if (v == null) {
@@ -295,7 +295,7 @@ public class ResourceManagerHandler extends RequestHandlerBase implements Permis
}
});
try {
- pool.getResourceManagerPlugin().setResourceLimits(managedComponent2, newLimits);
+ pool.setResourceLimits(managedComponent2, newLimits);
result.add("success", newLimits);
} catch (Exception e) {
log.warn("Error setting resource limits of " + resName + "/" + poolName + " : " + e.toString(), e);
diff --git a/solr/core/src/java/org/apache/solr/managed/ManagedComponent.java b/solr/core/src/java/org/apache/solr/managed/ChangeListener.java
similarity index 58%
copy from solr/core/src/java/org/apache/solr/managed/ManagedComponent.java
copy to solr/core/src/java/org/apache/solr/managed/ChangeListener.java
index 4ea5922..49fbad6 100644
--- a/solr/core/src/java/org/apache/solr/managed/ManagedComponent.java
+++ b/solr/core/src/java/org/apache/solr/managed/ChangeListener.java
@@ -17,24 +17,18 @@
package org.apache.solr.managed;
/**
- * A managed component.
+ *
*/
-public interface ManagedComponent extends AutoCloseable {
- /**
- * Unique name of this component. By convention id-s form a colon-separated hierarchy.
- */
- ManagedComponentId getManagedComponentId();
-
- void initializeManagedComponent(ResourceManager resourceManager, String poolName, String... otherPools);
+public interface ChangeListener {
/**
- * Component context used for managing additional component state for the purpose of resource management.
+ * Notify about changing a limit of a resource.
+ * @param poolName pool name where resource is managed.
+ * @param component managed component
+ * @param limitName limit name
+ * @param newRequestedVal requested new value of the resource limit.
+ * @param newActualVal actual value applied to the resource configuration. Note: this may differ from the
+ * value requested due to internal logic of the component.
*/
- ManagedContext getManagedContext();
-
- default void close() throws Exception {
- if (getManagedContext() != null) {
- getManagedContext().close();
- }
- }
+ void changedLimit(String poolName, ManagedComponent component, String limitName, Object newRequestedVal, Object newActualVal);
}
diff --git a/solr/core/src/java/org/apache/solr/managed/DefaultResourceManager.java b/solr/core/src/java/org/apache/solr/managed/DefaultResourceManager.java
index 069628d..6042717 100644
--- a/solr/core/src/java/org/apache/solr/managed/DefaultResourceManager.java
+++ b/solr/core/src/java/org/apache/solr/managed/DefaultResourceManager.java
@@ -33,7 +33,7 @@ import org.apache.solr.common.util.IOUtils;
import org.apache.solr.common.util.TimeSource;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrResourceLoader;
-import org.apache.solr.managed.types.CacheManagerPlugin;
+import org.apache.solr.managed.types.CacheManagerPool;
import org.apache.solr.search.SolrCache;
import org.apache.solr.util.DefaultSolrThreadFactory;
import org.slf4j.Logger;
@@ -60,7 +60,7 @@ public class DefaultResourceManager extends ResourceManager {
static {
Map<String, Object> params = new HashMap<>();
- params.put(CommonParams.TYPE, CacheManagerPlugin.TYPE);
+ params.put(CommonParams.TYPE, CacheManagerPool.TYPE);
// unlimited RAM
params.put(SolrCache.MAX_RAM_MB_PARAM, -1L);
DEFAULT_NODE_POOLS.put(NODE_SEARCHER_CACHE_POOL, params);
@@ -82,7 +82,7 @@ public class DefaultResourceManager extends ResourceManager {
protected boolean isClosed = false;
protected boolean enabled = true;
- protected ResourceManagerPluginFactory resourceManagerPluginFactory;
+ protected ResourceManagerPoolFactory resourceManagerPoolFactory;
protected SolrResourceLoader loader;
@@ -97,7 +97,7 @@ public class DefaultResourceManager extends ResourceManager {
scheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true);
scheduledThreadPoolExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
// TODO: make configurable based on plugin info
- resourceManagerPluginFactory = new DefaultResourceManagerPluginFactory(loader,
+ resourceManagerPoolFactory = new DefaultResourceManagerPoolFactory(loader,
pluginInfo != null ?
(Map<String, Object>)pluginInfo.initArgs.toMap(new HashMap<>()).getOrDefault("plugins", Collections.emptyMap()) :
Collections.emptyMap());
@@ -118,7 +118,12 @@ public class DefaultResourceManager extends ResourceManager {
}
@Override
- public void createPool(String name, String type, Map<String, Object> poolLimits, Map<String, Object> args) throws Exception {
+ public ResourceManagerPoolFactory getResourceManagerPoolFactory() {
+ return resourceManagerPoolFactory;
+ }
+
+ @Override
+ public ResourceManagerPool createPool(String name, String type, Map<String, Object> poolLimits, Map<String, Object> args) throws Exception {
ensureActive();
if (resourcePools.containsKey(name)) {
throw new IllegalArgumentException("Pool '" + name + "' already exists.");
@@ -126,16 +131,19 @@ public class DefaultResourceManager extends ResourceManager {
if (resourcePools.size() >= maxNumPools) {
throw new IllegalArgumentException("Maximum number of pools (" + maxNumPools + ") reached.");
}
- DefaultResourceManagerPool newPool = new DefaultResourceManagerPool(name, type, resourceManagerPluginFactory, poolLimits, args);
+ ResourceManagerPool newPool = resourceManagerPoolFactory.create(name, type, this, poolLimits, args);
newPool.scheduleDelaySeconds = Integer.parseInt(String.valueOf(args.getOrDefault(SCHEDULE_DELAY_SECONDS_PARAM, DEFAULT_SCHEDULE_DELAY_SECONDS)));
resourcePools.putIfAbsent(name, newPool);
- newPool.scheduledFuture = scheduledThreadPoolExecutor.scheduleWithFixedDelay(() -> {
- log.info("- running pool " + newPool.getName() + " / " + newPool.getType());
- newPool.run();
- }, 0,
- timeSource.convertDelay(TimeUnit.SECONDS, newPool.scheduleDelaySeconds, TimeUnit.MILLISECONDS),
- TimeUnit.MILLISECONDS);
+ if (timeSource != null) {
+ newPool.scheduledFuture = scheduledThreadPoolExecutor.scheduleWithFixedDelay(() -> {
+ log.info("- running pool " + newPool.getName() + " / " + newPool.getType());
+ newPool.manage();
+ }, 0,
+ timeSource.convertDelay(TimeUnit.SECONDS, newPool.scheduleDelaySeconds, TimeUnit.MILLISECONDS),
+ TimeUnit.MILLISECONDS);
+ }
log.info("- created pool " + newPool.getName() + " / " + newPool.getType());
+ return newPool;
}
@Override
diff --git a/solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPool.java b/solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPool.java
deleted file mode 100644
index f00866c..0000000
--- a/solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPool.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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.managed;
-
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This class manages a pool of resources of the same type, which use the same
- * {@link ResourceManagerPlugin} implementation for managing their resource limits.
- */
-public class DefaultResourceManagerPool implements ResourceManagerPool {
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
- private final Map<String, ManagedComponent> components = new ConcurrentHashMap<>();
- private Map<String, Object> poolLimits;
- private final String type;
- private final Class<? extends ManagedComponent> componentClass;
- private final String name;
- private final ResourceManagerPlugin resourceManagerPlugin;
- private final Map<String, Object> args;
- private final PoolContext poolContext = new PoolContext();
- private final ReentrantLock updateLock = new ReentrantLock();
- int scheduleDelaySeconds;
- ScheduledFuture<?> scheduledFuture;
-
- /**
- * Create a pool of resources to manage.
- * @param name unique name of the pool
- * @param type one of the supported pool types (see {@link ResourceManagerPluginFactory})
- * @param factory factory of {@link ResourceManagerPlugin}-s of the specified type
- * @param poolLimits pool limits (keys are controlled tags)
- * @param args parameters for the {@link ResourceManagerPlugin}
- * @throws Exception when initialization of the management plugin fails.
- */
- public DefaultResourceManagerPool(String name, String type, ResourceManagerPluginFactory factory, Map<String, Object> poolLimits, Map<String, Object> args) throws Exception {
- this.name = name;
- this.type = type;
- this.resourceManagerPlugin = factory.create(type, args);
- this.componentClass = factory.getComponentClassByType(type);
- this.poolLimits = new TreeMap<>(poolLimits);
- this.args = new HashMap<>(args);
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public String getType() {
- return type;
- }
-
- @Override
- public Map<String, Object> getParams() {
- return args;
- }
-
- @Override
- public ResourceManagerPlugin getResourceManagerPlugin() {
- return resourceManagerPlugin;
- }
-
- @Override
- public void registerComponent(ManagedComponent managedComponent) {
- if (!componentClass.isAssignableFrom(managedComponent.getClass())) {
- log.debug("Pool type '" + type + "' is not supported by the component " + managedComponent.getManagedComponentId());
- return;
- }
- ManagedComponent existing = components.putIfAbsent(managedComponent.getManagedComponentId().toString(), managedComponent);
- if (existing != null) {
- throw new IllegalArgumentException("Component '" + managedComponent.getManagedComponentId() + "' already exists in pool '" + name + "' !");
- }
- }
-
- @Override
- public boolean unregisterComponent(String name) {
- return components.remove(name) != null;
- }
-
- @Override
- public boolean isRegistered(String componentId) {
- return components.containsKey(componentId);
- }
-
- @Override
- public Map<String, ManagedComponent> getComponents() {
- return Collections.unmodifiableMap(components);
- }
-
- @Override
- public Map<String, Map<String, Object>> getCurrentValues() throws InterruptedException {
- updateLock.lockInterruptibly();
- try {
- // collect the current values
- Map<String, Map<String, Object>> currentValues = new HashMap<>();
- for (ManagedComponent managedComponent : components.values()) {
- try {
- currentValues.put(managedComponent.getManagedComponentId().toString(), resourceManagerPlugin.getMonitoredValues(managedComponent));
- } catch (Exception e) {
- log.warn("Error getting managed values from " + managedComponent.getManagedComponentId(), e);
- }
- }
- return Collections.unmodifiableMap(currentValues);
- } finally {
- updateLock.unlock();
- }
- }
-
- @Override
- public Map<String, Object> getPoolLimits() {
- return poolLimits;
- }
-
- @Override
- public void setPoolLimits(Map<String, Object> poolLimits) {
- this.poolLimits = new HashMap(poolLimits);
- }
-
- @Override
- public PoolContext getPoolContext() {
- return poolContext;
- }
-
- @Override
- public void run() {
- try {
- resourceManagerPlugin.manage(this);
- } catch (Exception e) {
- log.warn("Error running management plugin " + getName(), e);
- }
- }
-
- @Override
- public void close() throws IOException {
- if (scheduledFuture != null) {
- scheduledFuture.cancel(true);
- scheduledFuture = null;
- }
- components.clear();
- poolContext.clear();
- }
-}
diff --git a/solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPluginFactory.java b/solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPoolFactory.java
similarity index 55%
rename from solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPluginFactory.java
rename to solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPoolFactory.java
index 0f5cf79..3db59c7 100644
--- a/solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPluginFactory.java
+++ b/solr/core/src/java/org/apache/solr/managed/DefaultResourceManagerPoolFactory.java
@@ -22,39 +22,41 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.solr.core.SolrResourceLoader;
-import org.apache.solr.managed.types.CacheManagerPlugin;
+import org.apache.solr.managed.types.CacheManagerPool;
import org.apache.solr.search.SolrCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Default implementation of {@link ResourceManagerPluginFactory}.
+ * Default implementation of {@link ResourceManagerPoolFactory}.
*/
-public class DefaultResourceManagerPluginFactory implements ResourceManagerPluginFactory {
+public class DefaultResourceManagerPoolFactory implements ResourceManagerPoolFactory {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private static final Map<String, Class<? extends ResourceManagerPlugin>> typeToPluginClass = new HashMap<>();
+ private static final Map<String, Class<? extends ResourceManagerPool>> typeToPoolClass = new HashMap<>();
private static final Map<String, Class<? extends ManagedComponent>> typeToComponentClass = new HashMap<>();
- public static final String TYPE_TO_PLUGIN = "typeToPlugin";
+ public static final String TYPE_TO_POOL = "typeToPool";
public static final String TYPE_TO_COMPONENT = "typeToComponent";
static {
- typeToPluginClass.put(CacheManagerPlugin.TYPE, CacheManagerPlugin.class);
- typeToComponentClass.put(CacheManagerPlugin.TYPE, SolrCache.class);
+ typeToPoolClass.put(CacheManagerPool.TYPE, CacheManagerPool.class);
+ typeToPoolClass.put(NoOpResourceManager.NOOP, NoOpResourceManager.NoOpResourcePool.class);
+ typeToComponentClass.put(CacheManagerPool.TYPE, SolrCache.class);
+ typeToComponentClass.put(NoOpResourceManager.NOOP, NoOpResourceManager.NoOpManagedComponent.class);
}
private final SolrResourceLoader loader;
- public DefaultResourceManagerPluginFactory(SolrResourceLoader loader, Map<String, Object> config) {
+ public DefaultResourceManagerPoolFactory(SolrResourceLoader loader, Map<String, Object> config) {
this.loader = loader;
- Map<String, String> typeToPluginMap = (Map<String, String>)config.getOrDefault(TYPE_TO_PLUGIN, Collections.emptyMap());
+ Map<String, String> typeToPoolMap = (Map<String, String>)config.getOrDefault(TYPE_TO_POOL, Collections.emptyMap());
Map<String, String> typeToComponentMap = (Map<String, String>)config.getOrDefault(TYPE_TO_COMPONENT, Collections.emptyMap());
- Map<String, Class<? extends ResourceManagerPlugin>> newPlugins = new HashMap<>();
+ Map<String, Class<? extends ResourceManagerPool>> newPlugins = new HashMap<>();
Map<String, Class<? extends ManagedComponent>> newComponents = new HashMap<>();
- typeToPluginMap.forEach((type, className) -> {
+ typeToPoolMap.forEach((type, className) -> {
try {
- Class<? extends ResourceManagerPlugin> pluginClazz = loader.findClass(className, ResourceManagerPlugin.class);
+ Class<? extends ResourceManagerPool> pluginClazz = loader.findClass(className, ResourceManagerPool.class);
newPlugins.put(type, pluginClazz);
} catch (Exception e) {
log.warn("Error finding plugin class", e);
@@ -63,7 +65,7 @@ public class DefaultResourceManagerPluginFactory implements ResourceManagerPlugi
typeToComponentMap.forEach((type, className) -> {
try {
Class<? extends ManagedComponent> componentClazz = loader.findClass(className, ManagedComponent.class);
- if (typeToPluginClass.containsKey(type) || newPlugins.containsKey(type)) {
+ if (typeToPoolClass.containsKey(type) || newPlugins.containsKey(type)) {
newComponents.put(type, componentClazz);
}
} catch (Exception e) {
@@ -75,7 +77,7 @@ public class DefaultResourceManagerPluginFactory implements ResourceManagerPlugi
if (!newComponents.containsKey(type) && !typeToComponentClass.containsKey(type)) {
return;
}
- typeToPluginClass.put(type, pluginClass);
+ typeToPoolClass.put(type, pluginClass);
if (newComponents.containsKey(type)) {
typeToComponentClass.put(type, newComponents.get(type));
}
@@ -83,14 +85,23 @@ public class DefaultResourceManagerPluginFactory implements ResourceManagerPlugi
}
@Override
- public <T extends ManagedComponent> ResourceManagerPlugin<T> create(String type, Map<String, Object> params) throws Exception {
- Class<? extends ResourceManagerPlugin> pluginClazz = typeToPluginClass.get(type);
+ public <T extends ManagedComponent> ResourceManagerPool<T> create(String name, String type, ResourceManager resourceManager,
+ Map<String, Object> poolLimits, Map<String, Object> poolParams) throws Exception {
+ Class<? extends ResourceManagerPool> pluginClazz = typeToPoolClass.get(type);
if (pluginClazz == null) {
throw new IllegalArgumentException("Unsupported plugin type '" + type + "'");
}
- ResourceManagerPlugin<T> resourceManagerPlugin = loader.newInstance(pluginClazz.getName(), ResourceManagerPlugin.class);
- resourceManagerPlugin.init(params);
- return resourceManagerPlugin;
+ Class<? extends ManagedComponent> componentClass = typeToComponentClass.get(type);
+ if (componentClass == null) {
+ throw new IllegalArgumentException("Unsupported component type '" + type + "'");
+ }
+ ResourceManagerPool<T> resourceManagerPool = loader.newInstance(
+ pluginClazz.getName(),
+ ResourceManagerPool.class,
+ null,
+ new Class[]{String.class, String.class, ResourceManager.class, Map.class, Map.class},
+ new Object[]{name, type, resourceManager, poolLimits, poolParams});
+ return resourceManagerPool;
}
@Override
@@ -99,7 +110,7 @@ public class DefaultResourceManagerPluginFactory implements ResourceManagerPlugi
}
@Override
- public Class<? extends ResourceManagerPlugin> getPluginClassByType(String type) {
- return typeToPluginClass.get(type);
+ public Class<? extends ResourceManagerPool> getPoolClassByType(String type) {
+ return typeToPoolClass.get(type);
}
}
diff --git a/solr/core/src/java/org/apache/solr/managed/ManagedComponent.java b/solr/core/src/java/org/apache/solr/managed/ManagedComponent.java
index 4ea5922..df5c6c0 100644
--- a/solr/core/src/java/org/apache/solr/managed/ManagedComponent.java
+++ b/solr/core/src/java/org/apache/solr/managed/ManagedComponent.java
@@ -30,11 +30,11 @@ public interface ManagedComponent extends AutoCloseable {
/**
* Component context used for managing additional component state for the purpose of resource management.
*/
- ManagedContext getManagedContext();
+ SolrResourceContext getSolrResourceContext();
default void close() throws Exception {
- if (getManagedContext() != null) {
- getManagedContext().close();
+ if (getSolrResourceContext() != null) {
+ getSolrResourceContext().close();
}
}
}
diff --git a/solr/core/src/java/org/apache/solr/managed/ManagedComponentId.java b/solr/core/src/java/org/apache/solr/managed/ManagedComponentId.java
index 9b80e2d..9f47d4a 100644
--- a/solr/core/src/java/org/apache/solr/managed/ManagedComponentId.java
+++ b/solr/core/src/java/org/apache/solr/managed/ManagedComponentId.java
@@ -29,21 +29,18 @@ public class ManagedComponentId {
public static final String SEPARATOR = ":";
- private final String type;
private final String name;
private final String[] path;
private final String id;
- public ManagedComponentId(String type, Object component, String... path) {
- this(type, SolrMetricProducer.getUniqueMetricTag(component, null), path);
+ public ManagedComponentId(Object component, String... path) {
+ this(SolrMetricProducer.getUniqueMetricTag(component, null), path);
}
- ManagedComponentId(String type, String name, String... path) {
- this.type = type;
+ ManagedComponentId(String name, String... path) {
this.name = name;
this.path = path;
StringBuilder sb = new StringBuilder();
- sb.append(type);
if (path != null) {
for (String pathEl : path) {
if (sb.length() > 0) {
@@ -59,10 +56,6 @@ public class ManagedComponentId {
id = sb.toString();
}
- public String getType() {
- return type;
- }
-
public String getName() {
return name;
}
@@ -80,16 +73,12 @@ public class ManagedComponentId {
return null;
}
String[] parts = fullName.split(SEPARATOR);
- if (parts.length < 2) {
- throw new RuntimeException("at least 2 parts (type and name) must be present: " + fullName);
- }
- if (parts.length > 2) {
- String type = parts[0];
+ if (parts.length > 1) {
String name = parts[parts.length - 1];
- String[] path = Arrays.copyOfRange(parts, 1, parts.length - 1);
- return new ManagedComponentId(type, name, path);
+ String[] path = Arrays.copyOfRange(parts, 0, parts.length - 1);
+ return new ManagedComponentId(name, path);
} else {
- return new ManagedComponentId(parts[0], parts[1]);
+ return new ManagedComponentId(parts[0]);
}
}
}
\ No newline at end of file
diff --git a/solr/core/src/java/org/apache/solr/managed/NoOpResourceManager.java b/solr/core/src/java/org/apache/solr/managed/NoOpResourceManager.java
index 9dc0fc3..f6ce453 100644
--- a/solr/core/src/java/org/apache/solr/managed/NoOpResourceManager.java
+++ b/solr/core/src/java/org/apache/solr/managed/NoOpResourceManager.java
@@ -30,121 +30,49 @@ public class NoOpResourceManager extends ResourceManager {
public static final NoOpResourceManager INSTANCE = new NoOpResourceManager();
- private static final class NoOpResourceManagerPlugin implements ResourceManagerPlugin {
- static final NoOpResourceManagerPlugin INSTANCE = new NoOpResourceManagerPlugin();
-
- @Override
- public String getType() {
- return NOOP;
- }
-
- @Override
- public Collection<String> getMonitoredParams() {
- return Collections.emptySet();
- }
-
- @Override
- public Collection<String> getControlledParams() {
- return Collections.emptySet();
- }
-
- @Override
- public Map<String, Object> getMonitoredValues(ManagedComponent component) throws Exception {
- return Collections.emptyMap();
- }
-
+ public static class NoOpManagedComponent implements ManagedComponent {
@Override
- public void setResourceLimit(ManagedComponent component, String limitName, Object value) throws Exception {
- // no-op
+ public ManagedComponentId getManagedComponentId() {
+ return ManagedComponentId.of(NOOP);
}
@Override
- public Map<String, Object> getResourceLimits(ManagedComponent component) throws Exception {
- return Collections.emptyMap();
- }
+ public void initializeManagedComponent(ResourceManager resourceManager, String poolName, String... otherPools) {
- @Override
- public void manage(ResourceManagerPool pool) throws Exception {
- // no-op
}
@Override
- public void init(Map params) {
- // no-op
+ public SolrResourceContext getSolrResourceContext() {
+ return null;
}
}
- private static final class NoOpResourcePool implements ResourceManagerPool {
- static final NoOpResourcePool INSTANCE = new NoOpResourcePool();
-
- @Override
- public String getName() {
- return NOOP;
- }
-
- @Override
- public String getType() {
- return NOOP;
- }
+ public static final class NoOpResourcePool<NoOpManagedComponent> extends ResourceManagerPool {
+ static final NoOpResourcePool<NoOpResourceManager.NoOpManagedComponent> INSTANCE =
+ new NoOpResourcePool<>(NoOpResourceManager.INSTANCE, Collections.emptyMap(), Collections.emptyMap());
- @Override
- public ResourceManagerPlugin getResourceManagerPlugin() {
- return NoOpResourceManagerPlugin.INSTANCE;
+ public NoOpResourcePool(ResourceManager resourceManager, Map poolLimits, Map poolParams) {
+ super(NOOP, NOOP, resourceManager, poolLimits, poolParams);
}
@Override
- public void registerComponent(ManagedComponent managedComponent) {
- // no-op
- }
-
- @Override
- public boolean unregisterComponent(String name) {
- return false;
- }
-
- @Override
- public boolean isRegistered(String componentId) {
- return false;
- }
-
- @Override
- public Map<String, ManagedComponent> getComponents() {
+ public Map<String, Object> getMonitoredValues(ManagedComponent component) {
return Collections.emptyMap();
}
@Override
- public Map<String, Map<String, Object>> getCurrentValues() throws InterruptedException {
- return Collections.emptyMap();
+ protected Object doSetResourceLimit(ManagedComponent component, String limitName, Object value) throws Exception {
+ return value;
}
@Override
- public Map<String, Object> getPoolLimits() {
+ public Map<String, Object> getResourceLimits(ManagedComponent component) throws Exception {
return Collections.emptyMap();
}
@Override
- public Map<String, Object> getParams() {
- return Collections.emptyMap();
- }
+ protected void doManage() throws Exception {
- @Override
- public void setPoolLimits(Map<String, Object> poolLimits) {
- // no-op
- }
-
- @Override
- public PoolContext getPoolContext() {
- return null;
- }
-
- @Override
- public void close() throws IOException {
- // no-op
- }
-
- @Override
- public void run() {
- // no-op
}
}
@@ -154,8 +82,13 @@ public class NoOpResourceManager extends ResourceManager {
}
@Override
- public void createPool(String name, String type, Map<String, Object> poolLimits, Map<String, Object> args) throws Exception {
- // no-op
+ public ResourceManagerPoolFactory getResourceManagerPoolFactory() {
+ return null;
+ }
+
+ @Override
+ public ResourceManagerPool createPool(String name, String type, Map<String, Object> poolLimits, Map<String, Object> args) throws Exception {
+ return NoOpResourcePool.INSTANCE;
}
@Override
diff --git a/solr/core/src/java/org/apache/solr/managed/ResourceManager.java b/solr/core/src/java/org/apache/solr/managed/ResourceManager.java
index 364a99d..44b9c86 100644
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManager.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourceManager.java
@@ -30,7 +30,6 @@ import org.apache.solr.common.util.TimeSource;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.schema.FieldType;
-import org.apache.solr.util.SolrPluginUtils;
import org.apache.solr.util.plugin.PluginInfoInitialized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,7 +37,7 @@ import org.slf4j.LoggerFactory;
/**
* Base class for resource management. It uses a flat model where there are named
* resource pools of a given type, each pool with its own defined resource limits. Components can be added
- * to a pool for the management of a specific aspect of that component using {@link ResourceManagerPlugin}.
+ * to a pool for the management of a specific aspect of that component.
*/
public abstract class ResourceManager implements SolrCloseable, PluginInfoInitialized {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -162,14 +161,17 @@ public abstract class ResourceManager implements SolrCloseable, PluginInfoInitia
}
}
+ public abstract ResourceManagerPoolFactory getResourceManagerPoolFactory();
+
/**
* Create a named resource management pool.
- * @param name pool name
- * @param type pool type (one of the supported {@link ResourceManagerPlugin} types)
- * @param poolLimits pool limits
- * @param args other parameters. These are also used for creating a {@link ResourceManagerPlugin}
+ * @param name pool name (must not be empty)
+ * @param type pool type (one of the supported {@link ResourceManagerPool} types)
+ * @param poolLimits pool limits (must not be null)
+ * @param args other parameters (must not be null).
+ * @return newly created and scheduled resource pool
*/
- public abstract void createPool(String name, String type, Map<String, Object> poolLimits, Map<String, Object> args) throws Exception;
+ public abstract ResourceManagerPool createPool(String name, String type, Map<String, Object> poolLimits, Map<String, Object> args) throws Exception;
/**
* List all currently existing pool names.
diff --git a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPlugin.java b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPlugin.java
deleted file mode 100644
index dc6a5b6..0000000
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPlugin.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.managed;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A plugin that implements an algorithm for managing a pool of resources of a given type.
- */
-public interface ResourceManagerPlugin<T extends ManagedComponent> {
-
- /** Plugin symbolic type. */
- String getType();
-
- void init(Map<String, Object> params);
-
- /**
- * Name of monitored parameters that {@link ManagedComponent}-s managed by this plugin
- * are expected to support.
- */
- Collection<String> getMonitoredParams();
- /**
- * Name of controlled parameters that {@link ManagedComponent}-s managed by this plugin
- * are expected to support.
- */
- Collection<String> getControlledParams();
-
- /**
- * Return current values of monitored parameters. Note: the resulting map may contain also
- * other implementation-specific parameter values.
- * @param component monitored component
- */
- Map<String, Object> getMonitoredValues(T component) throws Exception;
-
- default void setResourceLimits(T component, Map<String, Object> limits) throws Exception {
- if (limits == null || limits.isEmpty()) {
- return;
- }
- for (Map.Entry<String, Object> entry : limits.entrySet()) {
- setResourceLimit(component, entry.getKey(), entry.getValue());
- }
- }
-
- void setResourceLimit(T component, String limitName, Object value) throws Exception;
-
- Map<String, Object> getResourceLimits(T component) throws Exception;
-
- /**
- * Manage resources in a pool. This method is called periodically by {@link ResourceManager},
- * according to a schedule defined by the pool.
- * @param pool pool instance.
- */
- void manage(ResourceManagerPool pool) throws Exception;
-
- /**
- * Return aggregated current monitored values.
- * <p>Default implementation of this method simply sums up all non-negative numeric values across
- * components and ignores any non-numeric values.</p>
- */
- default Map<String, Object> aggregateTotalValues(Map<String, Map<String, Object>> perComponentValues) {
- // calculate the totals
- Map<String, Object> newTotalValues = new HashMap<>();
- perComponentValues.values().forEach(map -> map.forEach((k, v) -> {
- // only calculate totals for numbers
- if (!(v instanceof Number)) {
- return;
- }
- Double val = ((Number)v).doubleValue();
- // -1 and MAX_VALUE are our special guard values
- if (val < 0 || val.longValue() == Long.MAX_VALUE || val.longValue() == Integer.MAX_VALUE) {
- return;
- }
- newTotalValues.merge(k, val, (v1, v2) -> ((Number)v1).doubleValue() + ((Number)v2).doubleValue());
- }));
- return newTotalValues;
- }
-}
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 4f1a786..dfa822f 100644
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPool.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPool.java
@@ -1,56 +1,216 @@
package org.apache.solr.managed;
import java.io.Closeable;
+import java.io.IOException;
+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.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
*
*/
-public interface ResourceManagerPool extends Runnable, Closeable {
+public abstract class ResourceManagerPool<T extends ManagedComponent> implements Closeable {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ protected final String name;
+ protected final String type;
+ protected Map<String, Object> poolLimits;
+ protected final Map<String, T> components = new ConcurrentHashMap<>();
+ protected final ResourceManager resourceManager;
+ protected final Class<? extends ManagedComponent> componentClass;
+ private final Map<String, Object> poolParams;
+ protected final ResourcePoolContext poolContext = new ResourcePoolContext();
+ protected final List<ChangeListener> listeners = new ArrayList<>();
+ protected final ReentrantLock updateLock = new ReentrantLock();
+ protected int scheduleDelaySeconds;
+ protected ScheduledFuture<?> scheduledFuture;
+
+ public ResourceManagerPool(String name, String type, ResourceManager resourceManager,
+ Map<String, Object> poolLimits, Map<String, Object> poolParams) {
+ this.name = name;
+ this.type = type;
+ this.resourceManager = resourceManager;
+ this.componentClass = resourceManager.getResourceManagerPoolFactory().getComponentClassByType(type);
+ this.poolLimits = new HashMap<>(poolLimits);
+ this.poolParams = new HashMap<>(poolParams);
+ }
/** Unique pool name. */
- String getName();
+ public String getName() {
+ return name;
+ }
/** Pool type. */
- String getType();
+ public String getType() {
+ return type;
+ }
- ResourceManagerPlugin getResourceManagerPlugin();
+ public ResourceManager getResourceManager() {
+ return resourceManager;
+ }
/** Add component to this pool. */
- void registerComponent(ManagedComponent managedComponent);
+ public void registerComponent(T managedComponent) {
+ if (!componentClass.isAssignableFrom(managedComponent.getClass())) {
+ log.debug("Pool type '" + type + "' is not supported by the component " + managedComponent.getManagedComponentId());
+ return;
+ }
+ ManagedComponent existing = components.putIfAbsent(managedComponent.getManagedComponentId().toString(), managedComponent);
+ if (existing != null) {
+ throw new IllegalArgumentException("Component '" + managedComponent.getManagedComponentId() + "' already exists in pool '" + name + "' !");
+ }
+ }
/** Remove named component from this pool. */
- boolean unregisterComponent(String componentId);
+ public boolean unregisterComponent(String componentId) {
+ return components.remove(name) != null;
+ }
/**
* Check whether a named component is registered in this pool.
* @param componentId component id
* @return true if the component with this name is registered, false otherwise.
*/
- boolean isRegistered(String componentId);
+ public boolean isRegistered(String componentId) {
+ return components.containsKey(componentId);
+ }
/** Get components managed by this pool. */
- Map<String, ManagedComponent> getComponents();
+ public Map<String, T> getComponents() {
+ return Collections.unmodifiableMap(components);
+ }
+
+ public void addChangeListener(ChangeListener listener) {
+ if (!listeners.contains(listener)) {
+ listeners.add(listener);
+ }
+ }
+
+ public void removeChangeListener(ChangeListener listener) {
+ listeners.remove(listener);
+ }
+
/**
* Get the current monitored values from all resources. Result is a map with resource names as keys,
* and param/value maps as values.
*/
- Map<String, Map<String, Object>> getCurrentValues() throws InterruptedException;
+ public Map<String, Map<String, Object>> getCurrentValues() throws InterruptedException {
+ updateLock.lockInterruptibly();
+ try {
+ // collect the current values
+ Map<String, Map<String, Object>> currentValues = new HashMap<>();
+ for (T managedComponent : components.values()) {
+ try {
+ currentValues.put(managedComponent.getManagedComponentId().toString(), getMonitoredValues(managedComponent));
+ } catch (Exception e) {
+ log.warn("Error getting managed values from " + managedComponent.getManagedComponentId(), e);
+ }
+ }
+ return Collections.unmodifiableMap(currentValues);
+ } finally {
+ updateLock.unlock();
+ }
+ }
- /** Get current pool limits. */
- Map<String, Object> getPoolLimits();
+ public abstract Map<String, Object> getMonitoredValues(T component) throws Exception;
- /** Get parameters specified during creation. */
- Map<String, Object> getParams();
+ public void setResourceLimits(T component, Map<String, Object> limits) throws Exception {
+ if (limits == null || limits.isEmpty()) {
+ return;
+ }
+ for (Map.Entry<String, Object> entry : limits.entrySet()) {
+ setResourceLimit(component, entry.getKey(), entry.getValue());
+ }
+ }
+
+ public Object setResourceLimit(T component, String limitName, Object value) throws Exception {
+ Object newActualLimit = doSetResourceLimit(component, limitName, value);
+ for (ChangeListener listener : listeners) {
+ listener.changedLimit(getName(), component, limitName, value, newActualLimit);
+ }
+ return newActualLimit;
+ }
+
+ protected abstract Object doSetResourceLimit(T component, String limitName, Object value) throws Exception;
+
+ public abstract Map<String, Object> getResourceLimits(T component) throws Exception;
+
+ /**
+ * Calculate aggregated monitored values.
+ * <p>Default implementation of this method simply sums up all non-negative numeric values across
+ * components and ignores any non-numeric values.</p>
+ */
+ public Map<String, Object> aggregateTotalValues(Map<String, Map<String, Object>> perComponentValues) {
+ // calculate the totals
+ Map<String, Object> newTotalValues = new HashMap<>();
+ perComponentValues.values().forEach(map -> map.forEach((k, v) -> {
+ // only calculate totals for numbers
+ if (!(v instanceof Number)) {
+ return;
+ }
+ Double val = ((Number)v).doubleValue();
+ // -1 and MAX_VALUE are our special guard values
+ if (val < 0 || val.longValue() == Long.MAX_VALUE || val.longValue() == Integer.MAX_VALUE) {
+ return;
+ }
+ newTotalValues.merge(k, val, (v1, v2) -> ((Number)v1).doubleValue() + ((Number)v2).doubleValue());
+ }));
+ return newTotalValues;
+ }
+
+ /** Get current pool limits. */
+ public Map<String, Object> getPoolLimits() {
+ return Collections.unmodifiableMap(poolLimits);
+ }
/**
* Pool limits are defined using controlled tags.
*/
- void setPoolLimits(Map<String, Object> poolLimits);
+ public void setPoolLimits(Map<String, Object> poolLimits) {
+ this.poolLimits = new HashMap(poolLimits);
+ }
+
+ /** Get parameters specified during creation. */
+ public Map<String, Object> getParams() {
+ return Collections.unmodifiableMap(poolParams);
+ }
/**
* Pool context used for managing additional pool state.
*/
- PoolContext getPoolContext();
+ public ResourcePoolContext getResourcePoolContext() {
+ return poolContext;
+ }
+
+ public void manage() {
+ updateLock.lock();
+ try {
+ doManage();
+ } catch (Exception e) {
+ log.warn("Exception caught managing pool " + getName(), e);
+ } finally {
+ updateLock.unlock();
+ }
+ }
+
+ protected abstract void doManage() throws Exception;
+
+ public void close() throws IOException {
+ if (scheduledFuture != null) {
+ scheduledFuture.cancel(true);
+ scheduledFuture = null;
+ }
+ components.clear();
+ poolContext.clear();
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPluginFactory.java b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPoolFactory.java
similarity index 67%
rename from solr/core/src/java/org/apache/solr/managed/ResourceManagerPluginFactory.java
rename to solr/core/src/java/org/apache/solr/managed/ResourceManagerPoolFactory.java
index 508b5e9..8110481 100644
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPluginFactory.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPoolFactory.java
@@ -19,16 +19,17 @@ package org.apache.solr.managed;
import java.util.Map;
/**
- * Factory for creating instances of {@link ResourceManagerPlugin}-s.
+ * Factory for creating instances of {@link ResourceManagerPool}-s.
*/
-public interface ResourceManagerPluginFactory {
+public interface ResourceManagerPoolFactory {
/**
- * Create a plugin of a given symbolic type.
- * @param type plugin symbolic type
- * @param params plugin parameters
+ * Create a pool of a given symbolic type.
+ * @param type pool symbolic type
+ * @param poolParams pool parameters
*/
- <T extends ManagedComponent> ResourceManagerPlugin<T> create(String type, Map<String, Object> params) throws Exception;
+ <T extends ManagedComponent> ResourceManagerPool<T> create(String name, String type, ResourceManager resourceManager,
+ Map<String, Object> poolLimits, Map<String, Object> poolParams) throws Exception;
/**
* Get the implementation class for a component of a given symbolic type.
@@ -40,5 +41,5 @@ public interface ResourceManagerPluginFactory {
* Get the implementation class for a plugin of a given symbolic type.
* @param type symbolic type
*/
- Class<? extends ResourceManagerPlugin> getPluginClassByType(String type);
+ Class<? extends ResourceManagerPool> getPoolClassByType(String type);
}
diff --git a/solr/core/src/java/org/apache/solr/managed/PoolContext.java b/solr/core/src/java/org/apache/solr/managed/ResourcePoolContext.java
similarity index 55%
rename from solr/core/src/java/org/apache/solr/managed/PoolContext.java
rename to solr/core/src/java/org/apache/solr/managed/ResourcePoolContext.java
index 221e1d0..dd1889c 100644
--- a/solr/core/src/java/org/apache/solr/managed/PoolContext.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourcePoolContext.java
@@ -5,5 +5,5 @@ import java.util.concurrent.ConcurrentHashMap;
/**
*
*/
-public class PoolContext extends ConcurrentHashMap<String, Object> {
+public class ResourcePoolContext extends ConcurrentHashMap<String, Object> {
}
diff --git a/solr/core/src/java/org/apache/solr/managed/ManagedContext.java b/solr/core/src/java/org/apache/solr/managed/SolrResourceContext.java
similarity index 90%
rename from solr/core/src/java/org/apache/solr/managed/ManagedContext.java
rename to solr/core/src/java/org/apache/solr/managed/SolrResourceContext.java
index f426d7c..09d86dce 100644
--- a/solr/core/src/java/org/apache/solr/managed/ManagedContext.java
+++ b/solr/core/src/java/org/apache/solr/managed/SolrResourceContext.java
@@ -24,12 +24,12 @@ import java.util.Set;
/**
*
*/
-public class ManagedContext implements Closeable {
+public class SolrResourceContext implements Closeable {
private final ResourceManager resourceManager;
private final String[] poolNames;
private final ManagedComponent component;
- public ManagedContext(ResourceManager resourceManager, ManagedComponent component, String poolName, String... otherPools) {
+ public SolrResourceContext(ResourceManager resourceManager, ManagedComponent component, String poolName, String... otherPools) {
this.resourceManager = resourceManager;
Set<String> pools = new LinkedHashSet<>();
pools.add(poolName);
diff --git a/solr/core/src/java/org/apache/solr/managed/types/CacheManagerPlugin.java b/solr/core/src/java/org/apache/solr/managed/types/CacheManagerPool.java
similarity index 61%
rename from solr/core/src/java/org/apache/solr/managed/types/CacheManagerPlugin.java
rename to solr/core/src/java/org/apache/solr/managed/types/CacheManagerPool.java
index 695b046..cee4fe7 100644
--- a/solr/core/src/java/org/apache/solr/managed/types/CacheManagerPlugin.java
+++ b/solr/core/src/java/org/apache/solr/managed/types/CacheManagerPool.java
@@ -17,19 +17,19 @@
package org.apache.solr.managed.types;
import java.lang.invoke.MethodHandles;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Function;
-import org.apache.solr.managed.ResourceManagerPlugin;
+import org.apache.solr.managed.ResourceManager;
import org.apache.solr.managed.ResourceManagerPool;
+import org.apache.solr.metrics.SolrMetricsContext;
import org.apache.solr.search.SolrCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * An implementation of {@link org.apache.solr.managed.ResourceManagerPlugin} specific to
+ * An implementation of {@link org.apache.solr.managed.ResourceManagerPool} specific to
* the management of {@link org.apache.solr.search.SolrCache} instances.
* <p>This plugin calculates the total size and maxRamMB of all registered cache instances
* and adjusts each cache's limits so that the aggregated values again fit within the pool limits.</p>
@@ -37,46 +37,39 @@ import org.slf4j.LoggerFactory;
* which can be adjusted using configuration parameter {@link #DEAD_BAND}. If monitored values don't
* exceed the limits +/- the dead band then no action is taken.</p>
*/
-public class CacheManagerPlugin implements ResourceManagerPlugin<SolrCache> {
+public class CacheManagerPool extends ResourceManagerPool<SolrCache> {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static String TYPE = "cache";
public static final String DEAD_BAND = "deadBand";
- public static final float DEFAULT_DEAD_BAND = 0.1f;
+ public static final double DEFAULT_DEAD_BAND = 0.1;
- protected static final Map<String, String> controlledToMonitored = new HashMap<>();
+ protected static final Map<String, Function<Map<String, Object>, Double>> controlledToMonitored = new HashMap<>();
static {
- controlledToMonitored.put(SolrCache.MAX_RAM_MB_PARAM, SolrCache.RAM_BYTES_USED_PARAM);
- controlledToMonitored.put(SolrCache.MAX_SIZE_PARAM, SolrCache.SIZE_PARAM);
+ controlledToMonitored.put(SolrCache.MAX_RAM_MB_PARAM, values -> {
+ Number ramBytes = (Number) values.get(SolrCache.RAM_BYTES_USED_PARAM);
+ return ramBytes != null ? ramBytes.doubleValue() / SolrCache.MB : 0.0;
+ });
+ controlledToMonitored.put(SolrCache.MAX_SIZE_PARAM, values ->
+ ((Number)values.getOrDefault(SolrCache.MAX_SIZE_PARAM, -1.0)).doubleValue());
}
- protected static final Collection<String> MONITORED_PARAMS = Arrays.asList(
- SolrCache.SIZE_PARAM,
- SolrCache.HIT_RATIO_PARAM,
- SolrCache.RAM_BYTES_USED_PARAM
- );
-
- protected static final Collection<String> CONTROLLED_PARAMS = Arrays.asList(
- SolrCache.MAX_RAM_MB_PARAM,
- SolrCache.MAX_SIZE_PARAM
- );
-
- protected float deadBand = DEFAULT_DEAD_BAND;
-
- @Override
- public Collection<String> getMonitoredParams() {
- return MONITORED_PARAMS;
- }
+ protected double deadBand = DEFAULT_DEAD_BAND;
- @Override
- public Collection<String> getControlledParams() {
- return CONTROLLED_PARAMS;
+ public CacheManagerPool(String name, String type, ResourceManager resourceManager, Map<String, Object> poolLimits, Map<String, Object> poolParams) {
+ super(name, type, resourceManager, poolLimits, poolParams);
+ String deadBandStr = String.valueOf(poolParams.getOrDefault(DEAD_BAND, DEFAULT_DEAD_BAND));
+ try {
+ deadBand = Double.parseDouble(deadBandStr);
+ } catch (Exception e) {
+ log.warn("Invalid deadBand parameter value '" + deadBandStr + "', using default " + DEFAULT_DEAD_BAND);
+ }
}
@Override
- public void setResourceLimit(SolrCache component, String limitName, Object val) {
+ public Object doSetResourceLimit(SolrCache component, String limitName, Object val) {
if (!(val instanceof Number)) {
try {
val = Long.parseLong(String.valueOf(val));
@@ -98,6 +91,7 @@ public class CacheManagerPlugin implements ResourceManagerPlugin<SolrCache> {
default:
throw new IllegalArgumentException("Unsupported limit name '" + limitName + "'");
}
+ return value.intValue();
}
@Override
@@ -110,60 +104,50 @@ public class CacheManagerPlugin implements ResourceManagerPlugin<SolrCache> {
@Override
public Map<String, Object> getMonitoredValues(SolrCache component) throws Exception {
- return component.getSolrMetricsContext().getMetricsSnapshot();
- }
-
- @Override
- public String getType() {
- return TYPE;
- }
-
- @Override
- public void init(Map<String, Object> params) {
- String deadBandStr = String.valueOf(params.getOrDefault(DEAD_BAND, DEFAULT_DEAD_BAND));
- try {
- deadBand = Float.parseFloat(deadBandStr);
- } catch (Exception e) {
- log.warn("Invalid deadBand parameter value '" + deadBandStr + "', using default " + DEFAULT_DEAD_BAND);
+ Map<String, Object> values = new HashMap<>();
+ values.put(SolrCache.SIZE_PARAM, component.size());
+ values.put(SolrCache.RAM_BYTES_USED_PARAM, component.ramBytesUsed());
+ SolrMetricsContext metricsContext = component.getSolrMetricsContext();
+ if (metricsContext != null) {
+ Map<String, Object> metrics = metricsContext.getMetricsSnapshot();
+ String hitRatioKey = component.getCategory().toString() + "." + metricsContext.getScope() + "." + SolrCache.HIT_RATIO_PARAM;
+ values.put(SolrCache.HIT_RATIO_PARAM, metrics.get(hitRatioKey));
}
+ return values;
}
@Override
- public void manage(ResourceManagerPool pool) throws Exception {
- Map<String, Map<String, Object>> currentValues = pool.getCurrentValues();
- Map<String, Object> totalValues = pool.getResourceManagerPlugin().aggregateTotalValues(currentValues);
+ protected void doManage() throws Exception {
+ Map<String, Map<String, Object>> currentValues = getCurrentValues();
+ Map<String, Object> totalValues = aggregateTotalValues(currentValues);
// pool limits are defined using controlled tags
- pool.getPoolLimits().forEach((poolLimitName, value) -> {
+ poolLimits.forEach((poolLimitName, value) -> {
// only numeric limits are supported
if (value == null || !(value instanceof Number)) {
return;
}
- float poolLimitValue = ((Number)value).floatValue();
+ double poolLimitValue = ((Number)value).doubleValue();
if (poolLimitValue <= 0) {
return;
}
- String monitoredTag = controlledToMonitored.get(poolLimitName);
- if (monitoredTag == null) {
- return;
- }
- Object tv = totalValues.get(monitoredTag);
- if (tv == null || !(tv instanceof Number)) {
+ Function<Map<String, Object>, Double> func = controlledToMonitored.get(poolLimitName);
+ if (func == null) {
return;
}
- Number totalValue = (Number) tv;
- if (totalValue.floatValue() <= 0.0f) {
+ Double totalValue = func.apply(totalValues);
+ if (totalValue.doubleValue() <= 0.0) {
return;
}
- float totalDelta = poolLimitValue - totalValue.floatValue();
+ double totalDelta = poolLimitValue - totalValue.doubleValue();
// dead band to avoid thrashing
if (Math.abs(totalDelta / poolLimitValue) < deadBand) {
return;
}
- float changeRatio = poolLimitValue / totalValue.floatValue();
- // modify current limits by the changeRatio
- pool.getComponents().forEach((name, component) -> {
+ double changeRatio = poolLimitValue / totalValue.doubleValue();
+ // modify evenly every component's current limits by the changeRatio
+ components.forEach((name, component) -> {
Map<String, Object> resourceLimits = getResourceLimits((SolrCache) component);
Object limit = resourceLimits.get(poolLimitName);
// XXX we could attempt here to control eg. ramBytesUsed by adjusting maxSize limit
@@ -171,11 +155,11 @@ public class CacheManagerPlugin implements ResourceManagerPlugin<SolrCache> {
if (limit == null || !(limit instanceof Number)) {
return;
}
- float currentResourceLimit = ((Number)limit).floatValue();
+ double currentResourceLimit = ((Number)limit).doubleValue();
if (currentResourceLimit <= 0) { // undefined or unsupported
return;
}
- float newLimit = currentResourceLimit * changeRatio;
+ double newLimit = currentResourceLimit * changeRatio;
try {
setResourceLimit((SolrCache) component, poolLimitName, newLimit);
} catch (Exception e) {
diff --git a/solr/core/src/java/org/apache/solr/managed/types/package-info.java b/solr/core/src/java/org/apache/solr/managed/types/package-info.java
index a7dde4d..5b8e137 100644
--- a/solr/core/src/java/org/apache/solr/managed/types/package-info.java
+++ b/solr/core/src/java/org/apache/solr/managed/types/package-info.java
@@ -16,7 +16,7 @@
*/
/**
- * Implementations of {@link org.apache.solr.managed.ResourceManagerPlugin} specialized for
+ * Implementations of {@link org.apache.solr.managed.ResourceManagerPool} specialized for
* particular types of objects.
*/
package org.apache.solr.managed.types;
diff --git a/solr/core/src/java/org/apache/solr/search/CaffeineCache.java b/solr/core/src/java/org/apache/solr/search/CaffeineCache.java
index 2002d4b..d40b319 100644
--- a/solr/core/src/java/org/apache/solr/search/CaffeineCache.java
+++ b/solr/core/src/java/org/apache/solr/search/CaffeineCache.java
@@ -36,9 +36,8 @@ import org.apache.lucene.util.Accountable;
import org.apache.lucene.util.RamUsageEstimator;
import org.apache.solr.common.SolrException;
import org.apache.solr.managed.ManagedComponentId;
-import org.apache.solr.managed.ManagedContext;
+import org.apache.solr.managed.SolrResourceContext;
import org.apache.solr.managed.ResourceManager;
-import org.apache.solr.managed.types.CacheManagerPlugin;
import org.apache.solr.metrics.MetricsMap;
import org.apache.solr.metrics.SolrMetricsContext;
import org.slf4j.Logger;
@@ -91,7 +90,7 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
private MetricsMap cacheMap;
private SolrMetricsContext solrMetricsContext;
- private ManagedContext managedContext;
+ private SolrResourceContext solrResourceContext;
private ManagedComponentId managedComponentId;
private long initialRamBytes = 0;
@@ -117,7 +116,7 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
}
str = (String) args.get(MAX_RAM_MB_PARAM);
int maxRamMB = str == null ? -1 : Double.valueOf(str).intValue();
- maxRamBytes = maxRamMB < 0 ? Long.MAX_VALUE : maxRamMB * 1024L * 1024L;
+ maxRamBytes = maxRamMB < 0 ? Long.MAX_VALUE : maxRamMB * MB;
str = (String) args.get(CLEANUP_THREAD_PARAM);
cleanupThread = str != null && Boolean.parseBoolean(str);
if (cleanupThread) {
@@ -265,12 +264,12 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
@Override
public int getMaxRamMB() {
- return maxRamBytes != Long.MAX_VALUE ? (int) (maxRamBytes / 1024L / 1024L) : -1;
+ return maxRamBytes != Long.MAX_VALUE ? (int) (maxRamBytes / MB) : -1;
}
@Override
public void setMaxRamMB(int maxRamMB) {
- long newMaxRamBytes = maxRamMB < 0 ? Long.MAX_VALUE : maxRamMB * 1024L * 1024L;
+ long newMaxRamBytes = maxRamMB < 0 ? Long.MAX_VALUE : maxRamMB * MB;
if (newMaxRamBytes != maxRamBytes) {
maxRamBytes = newMaxRamBytes;
Optional<Eviction<K, V>> evictionOpt = cache.policy().eviction();
@@ -388,13 +387,13 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
map.put("cumulative_evictions", cumulativeStats.evictionCount());
}
});
- solrMetricsContext.gauge(cacheMap, true, scope, getCategory().toString());
+ solrMetricsContext.gauge(cacheMap, true, null, getCategory().toString());
}
@Override
public void initializeManagedComponent(ResourceManager resourceManager, String poolName, String... otherPools) {
- managedComponentId = new ManagedComponentId(CacheManagerPlugin.TYPE, this, solrMetricsContext.getRegistryName(), getCategory().toString(), solrMetricsContext.getScope());
- managedContext = new ManagedContext(resourceManager, this, poolName, otherPools);
+ managedComponentId = new ManagedComponentId(this, solrMetricsContext.getRegistryName(), getCategory().toString(), solrMetricsContext.getScope());
+ solrResourceContext = new SolrResourceContext(resourceManager, this, poolName, otherPools);
}
@Override
@@ -403,7 +402,7 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
}
@Override
- public ManagedContext getManagedContext() {
- return managedContext;
+ public SolrResourceContext getSolrResourceContext() {
+ return solrResourceContext;
}
}
diff --git a/solr/core/src/java/org/apache/solr/search/SolrCache.java b/solr/core/src/java/org/apache/solr/search/SolrCache.java
index a8ead8c..ecc0308 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrCache.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrCache.java
@@ -55,6 +55,8 @@ public interface SolrCache<K,V> extends SolrInfoBean, ManagedComponent, Accounta
/** Use a background thread for cache evictions and cleanup. */
String CLEANUP_THREAD_PARAM = "cleanupThread";
+ long MB = 1024L * 1024L;
+
/**
* The initialization routine. Instance specific arguments are passed in
* the <code>args</code> map.
diff --git a/solr/core/src/java/org/apache/solr/search/SolrCacheHolder.java b/solr/core/src/java/org/apache/solr/search/SolrCacheHolder.java
index 5f1dbf8..8f4b3d6 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrCacheHolder.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrCacheHolder.java
@@ -22,7 +22,7 @@ import java.util.Map;
import java.util.function.Function;
import org.apache.solr.managed.ManagedComponentId;
-import org.apache.solr.managed.ManagedContext;
+import org.apache.solr.managed.SolrResourceContext;
import org.apache.solr.managed.ResourceManager;
import org.apache.solr.metrics.SolrMetricsContext;
import org.slf4j.Logger;
@@ -166,7 +166,7 @@ public class SolrCacheHolder<K, V> implements SolrCache<K,V> {
}
@Override
- public ManagedContext getManagedContext() {
- return delegate.getManagedContext();
+ public SolrResourceContext getSolrResourceContext() {
+ return delegate.getSolrResourceContext();
}
}
diff --git a/solr/core/src/test/org/apache/solr/managed/TestDefaultResourceManagerPool.java b/solr/core/src/test/org/apache/solr/managed/TestResourceManagerPool.java
similarity index 69%
rename from solr/core/src/test/org/apache/solr/managed/TestDefaultResourceManagerPool.java
rename to solr/core/src/test/org/apache/solr/managed/TestResourceManagerPool.java
index ebb9129..9294d23 100644
--- a/solr/core/src/test/org/apache/solr/managed/TestDefaultResourceManagerPool.java
+++ b/solr/core/src/test/org/apache/solr/managed/TestResourceManagerPool.java
@@ -1,8 +1,6 @@
package org.apache.solr.managed;
import java.lang.invoke.MethodHandles;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -23,7 +21,7 @@ import org.slf4j.LoggerFactory;
/**
*
*/
-public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
+public class TestResourceManagerPool extends SolrTestCaseJ4 {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final int SPEED = 50;
@@ -33,15 +31,8 @@ public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
private ResourceManager resourceManager;
private SolrResourceLoader loader;
- public interface MockManagedComponent extends ManagedComponent {
- int getFoo();
- int getBar();
- int getBaz();
- void setFoo(int foo);
- }
-
- public static class TestComponent implements MockManagedComponent {
- ManagedContext context;
+ public static class TestComponent implements ManagedComponent {
+ SolrResourceContext context;
ManagedComponentId id;
int foo, bar, baz;
@@ -49,22 +40,18 @@ public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
this.id = ManagedComponentId.of(id);
}
- @Override
public int getFoo() {
return foo;
}
- @Override
public int getBar() {
return bar;
}
- @Override
public int getBaz() {
return baz;
}
- @Override
public void setFoo(int foo) {
this.foo = foo;
this.bar = foo + 1;
@@ -78,19 +65,18 @@ public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
@Override
public void initializeManagedComponent(ResourceManager resourceManager, String poolName, String... otherPools) {
- context = new ManagedContext(resourceManager, this, poolName, otherPools);
+ context = new SolrResourceContext(resourceManager, this, poolName, otherPools);
}
@Override
- public ManagedContext getManagedContext() {
+ public SolrResourceContext getSolrResourceContext() {
return context;
}
}
- public static class MockManagerPlugin implements ResourceManagerPlugin<MockManagedComponent> {
-
- public MockManagerPlugin() {
-
+ public static class MockManagerPool extends ResourceManagerPool<TestComponent> {
+ public MockManagerPool(String name, String type, ResourceManager resourceManager, Map<String, Object> poolLimits, Map<String, Object> poolParams) {
+ super(name, type, resourceManager, poolLimits, poolParams);
}
@Override
@@ -99,22 +85,7 @@ public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
}
@Override
- public void init(Map<String, Object> params) {
-
- }
-
- @Override
- public Collection<String> getMonitoredParams() {
- return Arrays.asList("foo", "bar", "baz");
- }
-
- @Override
- public Collection<String> getControlledParams() {
- return Collections.singleton("foo");
- }
-
- @Override
- public Map<String, Object> getMonitoredValues(MockManagedComponent component) throws Exception {
+ public Map<String, Object> getMonitoredValues(TestComponent component) throws Exception {
Map<String, Object> result = new HashMap<>();
result.put("bar", component.getBar());
result.put("baz", component.getBaz());
@@ -123,36 +94,36 @@ public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
}
@Override
- public void setResourceLimit(MockManagedComponent component, String limitName, Object value) throws Exception {
+ public Object doSetResourceLimit(TestComponent component, String limitName, Object value) throws Exception {
if (limitName.equals("foo") && value instanceof Number) {
component.setFoo(((Number)value).intValue());
+ return ((Number)value).intValue();
} else {
throw new Exception("invalid limit name or value");
}
}
@Override
- public Map<String, Object> getResourceLimits(MockManagedComponent component) throws Exception {
+ public Map<String, Object> getResourceLimits(TestComponent component) throws Exception {
return Collections.singletonMap("foo", component.getFoo());
}
@Override
- public void manage(ResourceManagerPool pool) throws Exception {
+ public void doManage() throws Exception {
if (manageStartLatch.getCount() == 0) { // already fired
return;
}
manageStartLatch.countDown();
log.info("-- managing");
- Map<String, Map<String, Object>> currentValues = pool.getCurrentValues();
- Map<String, Object> totalValues = pool.getResourceManagerPlugin().aggregateTotalValues(currentValues);
- Map<String, Object> poolLimits = pool.getPoolLimits();
+ Map<String, Map<String, Object>> currentValues = getCurrentValues();
+ Map<String, Object> totalValues = aggregateTotalValues(currentValues);
if (poolLimits.containsKey("foo")) {
// manage
if (totalValues.containsKey("bar")) {
int totalValue = ((Number)totalValues.get("bar")).intValue();
int poolLimit = ((Number)poolLimits.get("foo")).intValue();
if (totalValue > poolLimit) {
- for (ManagedComponent cmp : pool.getComponents().values()) {
+ for (Object cmp : getComponents().values()) {
TestComponent component = (TestComponent)cmp;
int foo = component.getFoo();
if (foo > 0) {
@@ -175,10 +146,10 @@ public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
initArgs.put("plugins", config);
Map<String, String> plugins = new HashMap<>();
Map<String, String> components = new HashMap<>();
- config.put(DefaultResourceManagerPluginFactory.TYPE_TO_PLUGIN, plugins);
- config.put(DefaultResourceManagerPluginFactory.TYPE_TO_COMPONENT, components);
- plugins.put("mock", MockManagerPlugin.class.getName());
- components.put("mock", MockManagedComponent.class.getName());
+ config.put(DefaultResourceManagerPoolFactory.TYPE_TO_POOL, plugins);
+ config.put(DefaultResourceManagerPoolFactory.TYPE_TO_COMPONENT, components);
+ plugins.put("mock", MockManagerPool.class.getName());
+ components.put("mock", TestComponent.class.getName());
resourceManager.init(new PluginInfo("resourceManager", initArgs));
}
@@ -198,21 +169,21 @@ public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
resourceManager.createPool("test", "mock", Collections.singletonMap("foo", 10), Collections.emptyMap());
assertNotNull(resourceManager.getPool("test"));
for (int i = 0; i < 10; i++) {
- TestComponent component = new TestComponent("test:component:" + i);
+ TestComponent component = new TestComponent("component:" + i);
component.setFoo(i);
resourceManager.registerComponent("test", component);
}
ResourceManagerPool pool = resourceManager.getPool("test");
assertEquals(10, pool.getComponents().size());
Map<String, Map<String, Object>> currentValues = pool.getCurrentValues();
- Map<String, Object> totalValues = pool.getResourceManagerPlugin().aggregateTotalValues(currentValues);
+ Map<String, Object> totalValues = pool.aggregateTotalValues(currentValues);
assertNotNull(totalValues.get("bar"));
assertEquals(55, ((Number)totalValues.get("bar")).intValue());
assertNotNull(totalValues.get("baz"));
assertEquals(65, ((Number)totalValues.get("baz")).intValue());
- for (ManagedComponent cmp : pool.getComponents().values()) {
+ for (Object cmp : pool.getComponents().values()) {
TestComponent component = (TestComponent)cmp;
- Map<String, Object> limits = pool.getResourceManagerPlugin().getResourceLimits(component);
+ Map<String, Object> limits = pool.getResourceLimits(component);
assertEquals(1, limits.size());
assertNotNull(limits.get("foo"));
String name = component.getManagedComponentId().getName();
@@ -228,15 +199,15 @@ public class TestDefaultResourceManagerPool extends SolrTestCaseJ4 {
boolean await = manageFinishLatch.await(30000 / SPEED, TimeUnit.MILLISECONDS);
assertTrue("did not finish in time", await);
currentValues = pool.getCurrentValues();
- totalValues = pool.getResourceManagerPlugin().aggregateTotalValues(currentValues);
+ totalValues = pool.aggregateTotalValues(currentValues);
assertNotNull(totalValues.get("bar"));
assertEquals(46, ((Number)totalValues.get("bar")).intValue());
assertNotNull(totalValues.get("baz"));
assertEquals(56, ((Number)totalValues.get("baz")).intValue());
int changed = 0;
- for (ManagedComponent cmp : pool.getComponents().values()) {
+ for (Object cmp : pool.getComponents().values()) {
TestComponent component = (TestComponent)cmp;
- Map<String, Object> limits = pool.getResourceManagerPlugin().getResourceLimits(component);
+ Map<String, Object> limits = pool.getResourceLimits(component);
assertEquals(1, limits.size());
assertNotNull(limits.get("foo"));
String name = component.getManagedComponentId().getName();
diff --git a/solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPlugin.java b/solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPluginCloud.java
similarity index 59%
rename from solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPlugin.java
rename to solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPluginCloud.java
index dab094f..2abcca6 100644
--- a/solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPlugin.java
+++ b/solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPluginCloud.java
@@ -5,5 +5,5 @@ import org.apache.solr.cloud.SolrCloudTestCase;
/**
*
*/
-public class TestCacheManagerPlugin extends SolrCloudTestCase {
+public class TestCacheManagerPluginCloud extends SolrCloudTestCase {
}
diff --git a/solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPool.java b/solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPool.java
new file mode 100644
index 0000000..9e22158
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/managed/types/TestCacheManagerPool.java
@@ -0,0 +1,117 @@
+package org.apache.solr.managed.types;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.lucene.util.Accountable;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.managed.DefaultResourceManager;
+import org.apache.solr.managed.ManagedComponent;
+import org.apache.solr.managed.ResourceManager;
+import org.apache.solr.managed.ResourceManagerPool;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricsContext;
+import org.apache.solr.search.CaffeineCache;
+import org.apache.solr.search.NoOpRegenerator;
+import org.apache.solr.search.SolrCache;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class TestCacheManagerPool extends SolrTestCaseJ4 {
+
+ ResourceManager resourceManager;
+
+ @Before
+ public void setupTest() throws Exception {
+ initCore("solrconfig.xml", "schema.xml");
+ // disable automatic scheduling of pool runs
+ resourceManager = new DefaultResourceManager(h.getCore().getResourceLoader(), null);
+ resourceManager.init(null);
+ }
+
+ private static final long KB = 1024;
+ private static final long MB = 1024 * KB;
+
+ private static class ChangeListener implements org.apache.solr.managed.ChangeListener {
+ Map<String, Map<String, Object>> changedValues = new ConcurrentHashMap<>();
+
+ @Override
+ public void changedLimit(String poolName, ManagedComponent component, String limitName, Object newRequestedVal, Object newActualVal) {
+ Map<String, Object> perComponent = changedValues.computeIfAbsent(component.getManagedComponentId().toString(), id -> new ConcurrentHashMap<>());
+ perComponent.put(limitName, newActualVal);
+ }
+
+ public void clear() {
+ changedValues.clear();
+ }
+ }
+
+ @Test
+ public void testPoolLimits() throws Exception {
+ ResourceManagerPool pool = resourceManager.createPool("test", CacheManagerPool.TYPE, Collections.singletonMap("maxRamMB", 200), Collections.emptyMap());
+ SolrMetricManager metricManager = new SolrMetricManager();
+ SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, "fooRegistry", "barScope", "bazTag");
+ List<SolrCache> caches = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ SolrCache<String, Accountable> cache = new CaffeineCache<>();
+ Map<String, String> params = new HashMap<>();
+ params.put("maxRamMB", "50");
+ cache.init(params, null, new NoOpRegenerator());
+ cache.initializeMetrics(solrMetricsContext, "child-" + i);
+ cache.initializeManagedComponent(resourceManager, "test");
+ caches.add(cache);
+ }
+ ChangeListener listener = new ChangeListener();
+ pool.addChangeListener(listener);
+ // fill up all caches just below the global limit, evenly with small values
+ for (int i = 0; i < 202; i++) {
+ for (SolrCache<String, Accountable> cache : caches) {
+ cache.put("id-" + i, new Accountable() {
+ @Override
+ public long ramBytesUsed() {
+ return 100 * KB;
+ }
+ });
+ }
+ }
+ pool.manage();
+ Map<String, Object> totalValues = pool.aggregateTotalValues(pool.getCurrentValues());
+
+ assertEquals("should not adjust (within deadband): " + listener.changedValues.toString(), 0, listener.changedValues.size());
+ // add a few large values to exceed the total limit
+ // but without exceeding local (cache) limit
+ for (int i = 0; i < 10; i++) {
+ caches.get(0).put("large-" + i, new Accountable() {
+ @Override
+ public long ramBytesUsed() {
+ return 2560 * KB;
+ }
+ });
+ }
+ pool.manage();
+ totalValues = pool.aggregateTotalValues(pool.getCurrentValues());
+
+ assertEquals("should adjust all: " + listener.changedValues.toString(), 10, listener.changedValues.size());
+ listener.clear();
+ pool.manage();
+ totalValues = pool.aggregateTotalValues(pool.getCurrentValues());
+ assertEquals("should adjust all again: " + listener.changedValues.toString(), 10, listener.changedValues.size());
+ listener.clear();
+ pool.manage();
+ totalValues = pool.aggregateTotalValues(pool.getCurrentValues());
+ assertEquals("should not adjust (within deadband): " + listener.changedValues.toString(), 0, listener.changedValues.size());
+ }
+
+ @After
+ public void teardownTest() throws Exception {
+ resourceManager.close();
+ }
+}