You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ds...@apache.org on 2024/07/22 18:15:50 UTC

(solr) branch branch_9x updated: SOLR-17340: /admin/info/system optimization by caching BeanInfo (#2538)

This is an automated email from the ASF dual-hosted git repository.

dsmiley pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/branch_9x by this push:
     new c9da608800e SOLR-17340: /admin/info/system optimization by caching BeanInfo (#2538)
c9da608800e is described below

commit c9da608800e7bd76a6aa7dbd0a753621232cd30d
Author: Pierre Salagnac <82...@users.noreply.github.com>
AuthorDate: Mon Jul 22 20:12:07 2024 +0200

    SOLR-17340: /admin/info/system optimization by caching BeanInfo (#2538)
    
    Note the prefix arg was always null, thus this one-line change is just a refactoring for correctness.
    
    (cherry picked from commit 0da7a784353eefa9b37832bb6f557be81b7c03cf)
---
 solr/CHANGES.txt                                   |  2 +
 .../org/apache/solr/util/stats/MetricUtils.java    | 72 ++++++++++++++--------
 2 files changed, 47 insertions(+), 27 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index bd582fa6b69..bf08b204889 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -77,6 +77,8 @@ Optimizations
 
 * SOLR-17349: SolrDocumentFetcher should always skip lazy field loading overhead if documentCache==null (Michael Gibney)
 
+* SOLR-17340: Add cache on top of system metrics BeanInfos to make calls to /admin/info/system faster (Pierre Salagnac)
+
 Bug Fixes
 ---------------------
 * SOLR-12813: subqueries should respect basic auth. (Rudy Seitz via Eric Pugh)
diff --git a/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java b/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java
index 1e14ae452fa..95b6d7556ad 100644
--- a/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java
+++ b/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java
@@ -40,6 +40,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.SortedSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
@@ -64,30 +66,37 @@ public class MetricUtils {
   public static final String VALUE = "value";
   public static final String VALUES = "values";
 
-  static final String MS = "_ms";
+  private static final String MS = "_ms";
 
-  static final String MIN = "min";
-  static final String MIN_MS = MIN + MS;
-  static final String MAX = "max";
-  static final String MAX_MS = MAX + MS;
-  static final String MEAN = "mean";
-  static final String MEAN_MS = MEAN + MS;
-  static final String MEDIAN = "median";
-  static final String MEDIAN_MS = MEDIAN + MS;
-  static final String STDDEV = "stddev";
-  static final String STDDEV_MS = STDDEV + MS;
-  static final String SUM = "sum";
-  static final String P75 = "p75";
-  static final String P75_MS = P75 + MS;
-  static final String P95 = "p95";
-  static final String P95_MS = P95 + MS;
-  static final String P99 = "p99";
-  static final String P99_MS = P99 + MS;
-  static final String P999 = "p999";
-  static final String P999_MS = P999 + MS;
+  private static final String MIN = "min";
+  private static final String MIN_MS = MIN + MS;
+  private static final String MAX = "max";
+  private static final String MAX_MS = MAX + MS;
+  private static final String MEAN = "mean";
+  private static final String MEAN_MS = MEAN + MS;
+  private static final String MEDIAN = "median";
+  private static final String MEDIAN_MS = MEDIAN + MS;
+  private static final String STDDEV = "stddev";
+  private static final String STDDEV_MS = STDDEV + MS;
+  private static final String SUM = "sum";
+  private static final String P75 = "p75";
+  private static final String P75_MS = P75 + MS;
+  private static final String P95 = "p95";
+  private static final String P95_MS = P95 + MS;
+  private static final String P99 = "p99";
+  private static final String P99_MS = P99 + MS;
+  private static final String P999 = "p999";
+  private static final String P999_MS = P999 + MS;
 
   public static final Predicate<CharSequence> ALL_PROPERTIES = (name) -> true;
 
+  /**
+   * Local cache for BeanInfo instances that are created to scan for system metrics. List of
+   * properties is not supposed to change for the JVM lifespan, so we can keep already create
+   * BeanInfo instance for future calls.
+   */
+  private static final ConcurrentMap<Class<?>, BeanInfo> beanInfos = new ConcurrentHashMap<>();
+
   /**
    * Adds metrics from a Timer to a NamedList, using well-known back-compat names.
    *
@@ -764,12 +773,21 @@ public class MetricUtils {
   public static <T extends PlatformManagedObject> void addMXBeanMetrics(
       T obj, Class<? extends T> intf, String prefix, BiConsumer<String, Metric> consumer) {
     if (intf.isInstance(obj)) {
-      BeanInfo beanInfo;
-      try {
-        beanInfo =
-            Introspector.getBeanInfo(intf, intf.getSuperclass(), Introspector.IGNORE_ALL_BEANINFO);
-      } catch (IntrospectionException e) {
-        log.warn("Unable to fetch properties of MXBean {}", obj.getClass().getName());
+      BeanInfo beanInfo =
+          beanInfos.computeIfAbsent(
+              intf,
+              clazz -> {
+                try {
+                  return Introspector.getBeanInfo(
+                      clazz, clazz.getSuperclass(), Introspector.IGNORE_ALL_BEANINFO);
+
+                } catch (IntrospectionException e) {
+                  log.warn("Unable to fetch properties of MXBean {}", obj.getClass().getName());
+                  return null;
+                }
+              });
+
+      if (beanInfo == null) {
         return;
       }
       for (final PropertyDescriptor desc : beanInfo.getPropertyDescriptors()) {
@@ -827,7 +845,7 @@ public class MetricUtils {
       try {
         final Class<? extends PlatformManagedObject> intf =
             Class.forName(clazz).asSubclass(PlatformManagedObject.class);
-        MetricUtils.addMXBeanMetrics(obj, intf, null, consumer);
+        MetricUtils.addMXBeanMetrics(obj, intf, prefix, consumer);
       } catch (ClassNotFoundException e) {
         // ignore
       }