lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a.@apache.org
Subject [lucene-solr] 08/36: Next iteration.
Date Wed, 18 Dec 2019 16:38:46 GMT
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 adde6ba2b4dd6e91a72aec891d929a481155b897
Author: Andrzej Bialecki <ab@apache.org>
AuthorDate: Thu Jul 4 13:18:48 2019 +0200

    Next iteration.
---
 .../solr/managed/DefaultResourceManager.java       |  21 ++++-
 .../apache/solr/managed/ManagedMetricProducer.java |  36 +++++++
 .../org/apache/solr/managed/ManagedResource.java   |   6 +-
 .../org/apache/solr/managed/ResourceManager.java   |  12 ++-
 .../apache/solr/managed/ResourceManagerPlugin.java |   2 +-
 .../apache/solr/managed/ResourceManagerPool.java   | 103 +++++++++++++++------
 .../solr/managed/plugins/CacheManagerPlugin.java   |  47 ++++++----
 7 files changed, 166 insertions(+), 61 deletions(-)

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 743b1d9..3f51897 100644
--- a/solr/core/src/java/org/apache/solr/managed/DefaultResourceManager.java
+++ b/solr/core/src/java/org/apache/solr/managed/DefaultResourceManager.java
@@ -18,7 +18,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- *
+ * Default implementation of {@link ResourceManager}.
  */
 public class DefaultResourceManager extends ResourceManager {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -75,7 +75,7 @@ public class DefaultResourceManager extends ResourceManager {
   }
 
   @Override
-  public void createPool(String name, String type, Map<String, Float> limits, Map<String,
Object> params) throws Exception {
+  public void createPool(String name, String type, Map<String, Float> poolLimits, Map<String,
Object> params) throws Exception {
     ensureNotClosed();
     if (resourcePools.containsKey(name)) {
       throw new IllegalArgumentException("Pool '" + name + "' already exists.");
@@ -83,7 +83,7 @@ public class DefaultResourceManager extends ResourceManager {
     if (resourcePools.size() >= maxNumPools) {
       throw new IllegalArgumentException("Maximum number of pools (" + maxNumPools + ") reached.");
     }
-    ResourceManagerPool newPool = new ResourceManagerPool(name, type, resourceManagerPluginFactory,
limits, params);
+    ResourceManagerPool newPool = new ResourceManagerPool(name, type, resourceManagerPluginFactory,
poolLimits, params);
     newPool.scheduleDelaySeconds = Integer.parseInt(String.valueOf(params.getOrDefault(SCHEDULE_DELAY_SECONDS_PARAM,
DEFAULT_SCHEDULE_DELAY_SECONDS)));
     resourcePools.putIfAbsent(name, newPool);
     newPool.scheduledFuture = scheduledThreadPoolExecutor.scheduleWithFixedDelay(newPool,
0,
@@ -92,13 +92,13 @@ public class DefaultResourceManager extends ResourceManager {
   }
 
   @Override
-  public void modifyPoolLimits(String name, Map<String, Float> limits) throws Exception
{
+  public void modifyPoolLimits(String name, Map<String, Float> poolLimits) throws Exception
{
     ensureNotClosed();
     ResourceManagerPool pool = resourcePools.get(name);
     if (pool == null) {
       throw new IllegalArgumentException("Pool '" + name + "' doesn't exist.");
     }
-    pool.setLimits(limits);
+    pool.setPoolLimits(poolLimits);
   }
 
   @Override
@@ -118,6 +118,17 @@ public class DefaultResourceManager extends ResourceManager {
     if (pool == null) {
       throw new IllegalArgumentException("Pool '" + name + "' doesn't exist.");
     }
+    String type = pool.getType();
+    resourcePools.forEach((poolName, otherPool) -> {
+      if (otherPool == pool) {
+        return;
+      }
+      if (otherPool.getType().equals(type)) {
+        throw new IllegalArgumentException("Resource " + managedResource.getResourceName()
+
+            " is already managed in another pool (" +
+            otherPool.getName() + ") of the same type " + type);
+      }
+    });
     pool.addResource(managedResource);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/managed/ManagedMetricProducer.java b/solr/core/src/java/org/apache/solr/managed/ManagedMetricProducer.java
new file mode 100644
index 0000000..9f48702
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/managed/ManagedMetricProducer.java
@@ -0,0 +1,36 @@
+package org.apache.solr.managed;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.core.SolrInfoBean;
+
+/**
+ *
+ */
+public interface ManagedMetricProducer extends SolrInfoBean, ManagedResource {
+
+  @Override
+  default Map<String, Float> getManagedValues(Collection<String> tags) {
+    Map<String, Object> metrics = getMetricsSnapshot();
+    if (metrics == null) {
+      return Collections.emptyMap();
+    }
+    Map<String, Float> result = new HashMap<>();
+    tags.forEach(tag -> {
+      Object value = metrics.get(tag);
+      if (value == null || !(value instanceof Number)) {
+        return;
+      }
+      result.put(tag, ((Number)value).floatValue());
+    });
+    return result;
+  }
+
+  @Override
+  default String getResourceName() {
+    return getName();
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/managed/ManagedResource.java b/solr/core/src/java/org/apache/solr/managed/ManagedResource.java
index 04d5207..1351a76 100644
--- a/solr/core/src/java/org/apache/solr/managed/ManagedResource.java
+++ b/solr/core/src/java/org/apache/solr/managed/ManagedResource.java
@@ -16,7 +16,7 @@ public interface ManagedResource {
   /**
    * Unique name of this resource.
    */
-  String getName();
+  String getResourceName();
 
   /**
    * Returns types of management schemes supported by this resource. This always
@@ -37,7 +37,7 @@ public interface ManagedResource {
         setManagedLimit(key, value);
       } catch (Exception e) {
         log.warn("Exception setting managed limit on {}: key={}, value={}, exception={}",
-            getName(), key, value, e);
+            getResourceName(), key, value, e);
       }
     });
   }
@@ -59,5 +59,5 @@ public interface ManagedResource {
    * @param tags value names
    * @return map of names to current values.
    */
-  Map<String, Float> getManagedValues(Collection<String> tags);
+  Map<String, Float> getManagedValues(Collection<String> tags) throws Exception;
 }
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 e808bdb..a49f5d7 100644
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManager.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourceManager.java
@@ -17,7 +17,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- *
+ * Base class for resource management. It represents a flat model where there are named
+ * resource pools of a given type, each pool with its own defined limits. Resources can be
added
+ * to a pool for management of a specific aspect of that resource using {@link ResourceManagerPlugin}.
  */
 public abstract class ResourceManager implements SolrCloseable, PluginInfoInitialized {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -63,20 +65,20 @@ public abstract class ResourceManager implements SolrCloseable, PluginInfoInitia
 
   protected abstract void doInit() throws Exception;
 
-  public abstract void createPool(String name, String type, Map<String, Float> limits,
Map<String, Object> params) throws Exception;
+  public abstract void createPool(String name, String type, Map<String, Float> poolLimits,
Map<String, Object> params) throws Exception;
 
-  public abstract void modifyPoolLimits(String name, Map<String, Float> limits) throws
Exception;
+  public abstract void modifyPoolLimits(String name, Map<String, Float> poolLimits)
throws Exception;
 
   public abstract void removePool(String name) throws Exception;
 
-  public void addResources(String pool, Collection<ManagedResource> managedResource)
{
+  public void addResources(String pool, Collection<ManagedResource> managedResource)
throws Exception {
     ensureNotClosed();
     for (ManagedResource resource : managedResource) {
       addResource(pool, resource);
     }
   }
 
-  public abstract void addResource(String pool, ManagedResource managedResource);
+  public abstract void addResource(String pool, ManagedResource managedResource) throws Exception;
 
   protected void ensureNotClosed() {
     if (isClosed()) {
diff --git a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPlugin.java b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPlugin.java
index a73cdcb..0b00198 100644
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPlugin.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPlugin.java
@@ -15,6 +15,6 @@ public interface ResourceManagerPlugin {
   Collection<String> getMonitoredTags();
   Collection<String> getControlledTags();
 
-  void manage(ResourceManagerPool pool);
+  void manage(ResourceManagerPool pool) throws Exception;
 
 }
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 952dbb5..a1c437a 100644
--- a/solr/core/src/java/org/apache/solr/managed/ResourceManagerPool.java
+++ b/solr/core/src/java/org/apache/solr/managed/ResourceManagerPool.java
@@ -7,33 +7,46 @@ import java.util.Collection;
 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;
 
 /**
- *
+ * A pool of resources of the same type, which use the same {@link ResourceManagerPlugin}
for managing their
+ * resource use.
  */
 public class ResourceManagerPool implements Runnable, Closeable {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   private final Map<String, ManagedResource> resources = new ConcurrentHashMap<>();
-  private Map<String, Float> limits;
+  private Map<String, Float> poolLimits;
   private final String type;
   private final String name;
   private final ResourceManagerPlugin resourceManagerPlugin;
   private final Map<String, Object> params;
   private Map<String, Float> totalValues = null;
+  private final ReentrantLock updateLock = new ReentrantLock();
   int scheduleDelaySeconds;
   ScheduledFuture<?> scheduledFuture;
 
-  public ResourceManagerPool(String name, String type, ResourceManagerPluginFactory factory,
Map<String, Float> limits, Map<String, Object> params) throws Exception {
+  /**
+   * 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 params parameters for the {@link ResourceManagerPlugin}
+   * @throws Exception
+   */
+  public ResourceManagerPool(String name, String type, ResourceManagerPluginFactory factory,
Map<String, Float> poolLimits, Map<String, Object> params) throws Exception {
     this.name = name;
     this.type = type;
     this.resourceManagerPlugin = factory.create(type, params);
-    this.limits = new HashMap<>(limits);
+    this.poolLimits = new TreeMap<>(poolLimits);
     this.params = new HashMap<>(params);
   }
 
@@ -41,15 +54,19 @@ public class ResourceManagerPool implements Runnable, Closeable {
     return name;
   }
 
+  public String getType() {
+    return type;
+  }
+
   public void addResource(ManagedResource managedResource) {
     Collection<String> types = managedResource.getManagedResourceTypes();
     if (!types.contains(type)) {
-      log.debug("Pool type '" + type + "' is not supported by the resource " + managedResource.getName());
+      log.debug("Pool type '" + type + "' is not supported by the resource " + managedResource.getResourceName());
       return;
     }
-    ManagedResource existing = resources.putIfAbsent(managedResource.getName(), managedResource);
+    ManagedResource existing = resources.putIfAbsent(managedResource.getResourceName(), managedResource);
     if (existing != null) {
-      throw new IllegalArgumentException("Resource '" + managedResource.getName() + "' already
exists in pool '" + name + "' !");
+      throw new IllegalArgumentException("Resource '" + managedResource.getResourceName()
+ "' already exists in pool '" + name + "' !");
     }
   }
 
@@ -57,44 +74,70 @@ public class ResourceManagerPool implements Runnable, Closeable {
     return Collections.unmodifiableMap(resources);
   }
 
-  public Map<String, Map<String, Float>> getCurrentValues() {
-    // collect current values
-    Map<String, Map<String, Float>> currentValues = new HashMap<>();
-    for (ManagedResource resource : resources.values()) {
-      currentValues.put(resource.getName(), resource.getManagedValues(resourceManagerPlugin.getMonitoredTags()));
-    }
-    // calculate totals
-    totalValues = new HashMap<>();
-    currentValues.values().forEach(map -> map.forEach((k, v) -> {
-      Float total = totalValues.get(k);
-      if (total == null) {
-        totalValues.put(k, v);
-      } else {
-        totalValues.put(k, total + v);
+  /**
+   * Get the current values from all resources. Result is a map with resource names as keys,
+   * and tag/value maps as values.
+   */
+  public Map<String, Map<String, Float>> getCurrentValues() throws InterruptedException
{
+    updateLock.lockInterruptibly();
+    try {
+      // collect current values
+      Map<String, Map<String, Float>> currentValues = new HashMap<>();
+      for (ManagedResource resource : resources.values()) {
+        try {
+          currentValues.put(resource.getResourceName(), resource.getManagedValues(resourceManagerPlugin.getMonitoredTags()));
+        } catch (Exception e) {
+          log.warn("Error getting managed values from " + resource.getResourceName(), e);
+        }
       }
-    }));
-    return Collections.unmodifiableMap(currentValues);
+      // calculate totals
+      Map<String, Float> newTotalValues = new HashMap<>();
+      currentValues.values().forEach(map -> map.forEach((k, v) -> {
+        Float total = newTotalValues.get(k);
+        if (total == null) {
+          newTotalValues.put(k, v);
+        } else {
+          newTotalValues.put(k, total + v);
+        }
+      }));
+      totalValues = newTotalValues;
+      return Collections.unmodifiableMap(currentValues);
+    } finally {
+      updateLock.unlock();
+    }
   }
 
   /**
    * This returns cumulative values of all resources. NOTE:
    * you must call {@link #getCurrentValues()} first!
    */
-  public Map<String, Float> getTotalValues() {
-    return Collections.unmodifiableMap(totalValues);
+  public Map<String, Float> getTotalValues() throws InterruptedException {
+    updateLock.lockInterruptibly();
+    try {
+      return Collections.unmodifiableMap(totalValues);
+    } finally {
+      updateLock.unlock();
+    }
   }
 
-  public Map<String, Float> getLimits() {
-    return limits;
+  public Map<String, Float> getPoolLimits() {
+    return poolLimits;
   }
 
-  public void setLimits(Map<String, Float> limits) {
-    this.limits = new HashMap(limits);
+  /**
+   * Pool limits are defined using controlled tags.
+   */
+  public void setPoolLimits(Map<String, Float> poolLimits) {
+    this.poolLimits = new HashMap(poolLimits);
   }
 
   @Override
   public void run() {
-    resourceManagerPlugin.manage(this);
+    try {
+      resourceManagerPlugin.manage(this);
+    } catch (Exception e) {
+      log.warn("Error running management plugin " + getName(), e);
+    }
   }
 
   @Override
diff --git a/solr/core/src/java/org/apache/solr/managed/plugins/CacheManagerPlugin.java b/solr/core/src/java/org/apache/solr/managed/plugins/CacheManagerPlugin.java
index 7f2f5cd..345dae4 100644
--- a/solr/core/src/java/org/apache/solr/managed/plugins/CacheManagerPlugin.java
+++ b/solr/core/src/java/org/apache/solr/managed/plugins/CacheManagerPlugin.java
@@ -1,5 +1,6 @@
 package org.apache.solr.managed.plugins;
 
+import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
@@ -7,11 +8,15 @@ import java.util.Map;
 
 import org.apache.solr.managed.AbstractResourceManagerPlugin;
 import org.apache.solr.managed.ResourceManagerPool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  *
  */
 public class CacheManagerPlugin extends AbstractResourceManagerPlugin {
+  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
   public static String TYPE = "cache";
 
   public static final String SIZE_TAG = "size";
@@ -58,36 +63,44 @@ public class CacheManagerPlugin extends AbstractResourceManagerPlugin
{
   }
 
   @Override
-  public void manage(ResourceManagerPool pool) {
+  public void manage(ResourceManagerPool pool) throws Exception {
     Map<String, Map<String, Float>> currentValues = pool.getCurrentValues();
     Map<String, Float> totalValues = pool.getTotalValues();
-    pool.getLimits().forEach((poolLimitName, poolLimitValue) -> {
+    // pool limits are defined using controlled tags
+    pool.getPoolLimits().forEach((poolLimitName, poolLimitValue) -> {
+      if (poolLimitValue == null || poolLimitValue <= 0) {
+        return;
+      }
       String monitoredTag = controlledToMonitored.get(poolLimitName);
       if (monitoredTag == null) {
         return;
       }
       Float totalValue = totalValues.get(monitoredTag);
-      if (totalValue == null) {
+      if (totalValue == null || totalValue <= 0.0f) {
         return;
       }
       float totalDelta = poolLimitValue - totalValue;
+
+      // 10% hysteresis to avoid thrashing
+      // TODO: make the threshold configurable
+      if (Math.abs(totalDelta / poolLimitValue) < 0.1f) {
+        return;
+      }
+
+      float changeRatio = poolLimitValue / totalValue;
+      // modify current limits by the changeRatio
       pool.getResources().forEach((name, resource) -> {
-        Map<String, Float> current = currentValues.get(name);
-        if (current == null) {
+        Map<String, Float> resourceLimits = resource.getManagedLimits();
+        Float currentResourceLimit = resourceLimits.get(poolLimitName);
+        if (currentResourceLimit == null || currentResourceLimit <= 0) {
           return;
         }
-        Map<String, Float> limits = resource.getManagedLimits();
-        Float managedSize = limits.get(SIZE_TAG);
-        Float resMaxRamMB = limits.get(MAX_RAM_MB_TAG);
-        Float currentSize = current.get(SIZE_TAG);
-        Float currentHitratio = current.get(HIT_RATIO_TAG);
-        Float ramBytesUsed = current.get(RAM_BYTES_USED_TAG);
-
-        // logic to adjust per-resource controlled limits
-        if (poolLimitName.equals(MAX_RAM_MB_TAG)) {
-          // adjust per-resource maxRamMB
-        } else if (poolLimitName.equals(SIZE_TAG)) {
-          // adjust per-resource size
+        float newLimit = currentResourceLimit * changeRatio;
+        try {
+          resource.setManagedLimit(poolLimitName, newLimit);
+        } catch (Exception e) {
+          log.warn("Failed to set managed limit " + poolLimitName +
+              " from " + currentResourceLimit + " to " + newLimit + " on " + resource.getResourceName(),
e);
         }
       });
     });


Mime
View raw message