You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2019/08/02 21:21:06 UTC

[lucene-solr] branch jira/SOLR-13677 updated: SOLR-13677: initial commit

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

noble pushed a commit to branch jira/SOLR-13677
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/jira/SOLR-13677 by this push:
     new 3ce75aa  SOLR-13677: initial commit
3ce75aa is described below

commit 3ce75aac49c79a023a9f1519badfe769e6a8f797
Author: Noble Paul <no...@apache.org>
AuthorDate: Sat Aug 3 07:19:40 2019 +1000

    SOLR-13677: initial commit
---
 .../solr/handler/dataimport/DataImportHandler.java |  2 +-
 .../apache/solr/handler/ReplicationHandler.java    | 39 +++++++++--------
 .../apache/solr/handler/RequestHandlerBase.java    | 14 +++++-
 .../solr/handler/component/SuggestComponent.java   | 15 +++++--
 .../org/apache/solr/metrics/SolrMetricManager.java | 50 ++++++++++++++++++----
 .../apache/solr/metrics/SolrMetricProducer.java    |  9 +++-
 .../java/org/apache/solr/search/FastLRUCache.java  |  4 +-
 .../src/java/org/apache/solr/search/LFUCache.java  |  4 +-
 .../src/java/org/apache/solr/search/LRUCache.java  |  4 +-
 .../org/apache/solr/search/SolrFieldCacheBean.java |  8 +++-
 .../org/apache/solr/search/SolrIndexSearcher.java  | 31 ++++++++------
 .../apache/solr/security/AuthenticationPlugin.java |  2 +-
 .../org/apache/solr/store/blockcache/Metrics.java  | 11 ++---
 .../solr/store/hdfs/HdfsLocalityReporter.java      | 11 ++---
 .../org/apache/solr/update/SolrIndexWriter.java    | 19 +++++---
 .../src/java/org/apache/solr/update/UpdateLog.java | 17 ++++++--
 ...rumentedPoolingHttpClientConnectionManager.java | 28 ++++++++----
 17 files changed, 188 insertions(+), 80 deletions(-)

diff --git a/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java b/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java
index 50938e4..037934a 100644
--- a/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java
+++ b/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java
@@ -299,7 +299,7 @@ public class DataImportHandler extends RequestHandlerBase implements
         map.put(DataImporter.MSG.TOTAL_DOCS_SKIPPED, cumulative.skipDocCount);
       }
     });
-    manager.registerGauge(this, registryName, metrics, tag, true, "importer", getCategory().toString(), scope);
+     myGauges.add( manager.registerGauge(this, registryName, metrics, tag, true, "importer", getCategory().toString(), scope));
   }
 
   // //////////////////////SolrInfoMBeans methods //////////////////////
diff --git a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
index dc1d1b1..402cf4a 100644
--- a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
@@ -866,18 +866,18 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
   public void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
     super.initializeMetrics(manager, registry, tag, scope);
 
-    manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? NumberUtils.readableSize(core.getIndexSize()) : ""),
-        tag, true, "indexSize", getCategory().toString(), scope);
-    manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? getIndexVersion().toString() : ""),
-        tag, true, "indexVersion", getCategory().toString(), scope);
-    manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? getIndexVersion().generation : 0),
-        tag, true, GENERATION, getCategory().toString(), scope);
-    manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? core.getIndexDir() : ""),
-        tag, true, "indexPath", getCategory().toString(), scope);
-    manager.registerGauge(this, registry, () -> isMaster,
-        tag, true, "isMaster", getCategory().toString(), scope);
-    manager.registerGauge(this, registry, () -> isSlave,
-        tag, true, "isSlave", getCategory().toString(), scope);
+    myGauges.add(manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? NumberUtils.readableSize(core.getIndexSize()) : ""),
+        tag, true, "indexSize", getCategory().toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? getIndexVersion().toString() : ""),
+        tag, true, "indexVersion", getCategory().toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? getIndexVersion().generation : 0),
+        tag, true, GENERATION, getCategory().toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? core.getIndexDir() : ""),
+        tag, true, "indexPath", getCategory().toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> isMaster,
+        tag, true, "isMaster", getCategory().toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> isSlave,
+        tag, true, "isSlave", getCategory().toString(), scope));
     final MetricsMap fetcherMap = new MetricsMap((detailed, map) -> {
       IndexFetcher fetcher = currentIndexFetcher;
       if (fetcher != null) {
@@ -906,13 +906,13 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
         addVal(map, IndexFetcher.CONF_FILES_REPLICATED, props, String.class);
       }
     });
-    manager.registerGauge(this, registry, fetcherMap, tag, true, "fetcher", getCategory().toString(), scope);
-    manager.registerGauge(this, registry, () -> isMaster && includeConfFiles != null ? includeConfFiles : "",
-        tag, true, "confFilesToReplicate", getCategory().toString(), scope);
-    manager.registerGauge(this, registry, () -> isMaster ? getReplicateAfterStrings() : Collections.<String>emptyList(),
-        tag, true, REPLICATE_AFTER, getCategory().toString(), scope);
-    manager.registerGauge(this, registry, () -> isMaster && replicationEnabled.get(),
-        tag, true, "replicationEnabled", getCategory().toString(), scope);
+    myGauges.add(manager.registerGauge(this, registry, fetcherMap, tag, true, "fetcher", getCategory().toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> isMaster && includeConfFiles != null ? includeConfFiles : "",
+        tag, true, "confFilesToReplicate", getCategory().toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> isMaster ? getReplicateAfterStrings() : Collections.<String>emptyList(),
+        tag, true, REPLICATE_AFTER, getCategory().toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> isMaster && replicationEnabled.get(),
+        tag, true, "replicationEnabled", getCategory().toString(), scope));
   }
 
   //TODO Should a failure retrieving any piece of info mark the overall request as a failure?  Is there a core set of values that are required to make a response here useful?
@@ -1388,6 +1388,7 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
   }
 
   public void close() {
+    super.close();
     if (executorService != null) executorService.shutdown();
     if (pollingIndexFetcher != null) {
       pollingIndexFetcher.destroy();
diff --git a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
index ee7923f..9a4bd0e 100644
--- a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
+++ b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
@@ -17,6 +17,7 @@
 package org.apache.solr.handler;
 
 import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
@@ -82,6 +83,7 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
   private MetricRegistry registry;
   protected String registryName;
   protected SolrMetricManager metricManager;
+  protected final ArrayList<SolrMetricManager.GaugeWrapper> myGauges = new ArrayList<>();
 
 
   @SuppressForbidden(reason = "Need currentTimeMillis, used only for stats output")
@@ -157,10 +159,10 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
     requests = manager.counter(this, registryName, "requests", getCategory().toString(), scope);
     MetricsMap metricsMap = new MetricsMap((detail, map) ->
       shardPurposes.forEach((k, v) -> map.put(k, v.getCount())));
-    manager.registerGauge(this, registryName, metricsMap, tag, true, "shardRequests", getCategory().toString(), scope);
+    myGauges.add(manager.registerGauge(this, registryName, metricsMap, tag, true, "shardRequests", getCategory().toString(), scope));
     requestTimes = manager.timer(this, registryName, "requestTimes", getCategory().toString(), scope);
     totalTime = manager.counter(this, registryName, "totalTime", getCategory().toString(), scope);
-    manager.registerGauge(this, registryName, () -> handlerStart, tag, true, "handlerStart", getCategory().toString(), scope);
+    myGauges.add(manager.registerGauge(this, registryName, () -> handlerStart, tag, true, "handlerStart", getCategory().toString(), scope));
   }
 
   public static SolrParams getSolrParamsFromNamedList(NamedList args, String key) {
@@ -323,6 +325,14 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
   public Collection<Api> getApis() {
     return ImmutableList.of(new ApiBag.ReqHandlerToApi(this, ApiBag.constructSpec(pluginInfo)));
   }
+
+  @Override
+  public void close()  {
+    for (SolrMetricManager.GaugeWrapper gauge : myGauges) {
+      gauge.unregister();
+    }
+    myGauges.clear();
+  }
 }
 
 
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
index 2d6fdb1..c2d05b7 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
@@ -350,19 +350,20 @@ public class SuggestComponent extends SearchComponent implements SolrCoreAware,
     return "Suggester component";
   }
 
+  List<SolrMetricManager.GaugeWrapper> myGauges = new ArrayList<>();
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registryName, String tag, String scope) {
     this.registryName = registryName;
     this.metricManager = manager;
     registry = manager.registry(registryName);
-    manager.registerGauge(this, registryName, () -> ramBytesUsed(), tag, true, "totalSizeInBytes", getCategory().toString(), scope);
+    myGauges.add(manager.registerGauge(this, registryName, () -> ramBytesUsed(), tag, true, "totalSizeInBytes", getCategory().toString(), scope));
     MetricsMap suggestersMap = new MetricsMap((detailed, map) -> {
       for (Map.Entry<String, SolrSuggester> entry : suggesters.entrySet()) {
         SolrSuggester suggester = entry.getValue();
         map.put(entry.getKey(), suggester.toString());
       }
     });
-    manager.registerGauge(this, registryName, suggestersMap, tag, true, "suggesters", getCategory().toString(), scope);
+    myGauges.add(manager.registerGauge(this, registryName, suggestersMap, tag, true, "suggesters", getCategory().toString(), scope));
   }
 
   @Override
@@ -373,7 +374,15 @@ public class SuggestComponent extends SearchComponent implements SolrCoreAware,
     }
     return sizeInBytes;
   }
-  
+
+  @Override
+  public void close() throws Exception {
+    for (SolrMetricManager.GaugeWrapper gauge : myGauges) {
+      gauge.unregister();
+    }
+    myGauges.clear();
+  }
+
   @Override
   public Collection<Accountable> getChildResources() {
     return Accountables.namedAccountables("field", suggesters);
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
index 6e01204..474deeb 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
@@ -18,6 +18,7 @@ package org.apache.solr.metrics;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -665,30 +666,63 @@ public class SolrMetricManager {
    * wrappers with the matching tag using {@link #unregisterGauges(String, String)}.
    */
   public static class GaugeWrapper<T> implements Gauge<T> {
-    private final Gauge<T> gauge;
+    private final WeakReference<Gauge<T>> gauge;
     private final String tag;
-
-    public GaugeWrapper(Gauge<T> gauge, String tag) {
-      this.gauge = gauge;
+    private final String registry;
+    private final SolrMetricManager solrMetricManager;
+    private boolean isUnregistered = false;
+    private static final Gauge NULL_GAUGE = () -> null;
+    private final String className;
+
+    public GaugeWrapper(Gauge<T> gauge, String tag, String registry, SolrMetricManager solrMetricManager) {
+      this.gauge = new WeakReference<>(gauge);
       this.tag = tag;
+      this.registry = registry;
+      this.solrMetricManager = solrMetricManager;
+      this.className = gauge.getClass().getName();
     }
 
     @Override
     public T getValue() {
-      return gauge.getValue();
+      return getGauge().getValue();
     }
 
+
     public String getTag() {
       return tag;
     }
 
     public Gauge<T> getGauge() {
-      return gauge;
+      Gauge<T> val = gauge.get();
+      if (val == null && !isUnregistered) {
+        log.warn("POSSIBLE MEMORY LEAK.DID NOT UNREGISTER metrics by:  {}", className);
+        unregister();
+      }
+      return val == null ? NULL_GAUGE : val;
     }
+
+
+    public void unregister() {
+      if(isUnregistered) return;
+      MetricRegistry registry = solrMetricManager.registry(this.registry);
+      registry.removeMatching((name, metric) -> {
+        if (metric instanceof GaugeWrapper &&
+            this == metric) {
+          return true;
+        } else {
+          return false;
+        }
+      });
+      isUnregistered = true;
+    }
+
+
   }
 
-  public void registerGauge(SolrInfoBean info, String registry, Gauge<?> gauge, String tag, boolean force, String metricName, String... metricPath) {
-    registerMetric(info, registry, new GaugeWrapper(gauge, tag), force, metricName, metricPath);
+  public GaugeWrapper registerGauge(SolrInfoBean info, String registry, Gauge<?> gauge, String tag, boolean force, String metricName, String... metricPath) {
+    GaugeWrapper gaugeWrapper = new GaugeWrapper(gauge, tag, registry, this);
+    registerMetric(info, registry, gaugeWrapper, force, metricName, metricPath);
+    return gaugeWrapper;
   }
 
   public int unregisterGauges(String registryName, String tag) {
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java
index d5c23b5..233bc5e 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java
@@ -19,7 +19,14 @@ package org.apache.solr.metrics;
 /**
  * Used by objects that expose metrics through {@link SolrCoreMetricManager}.
  */
-public interface SolrMetricProducer {
+public interface SolrMetricProducer extends AutoCloseable {
+
+  // in 9.0 every lcass will be forced to implement close and release their gauges
+  @Override
+  default void close() throws Exception{
+
+
+  }
 
   /**
    * Initializes metrics specific to this producer
diff --git a/solr/core/src/java/org/apache/solr/search/FastLRUCache.java b/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
index 8f19729..155c165 100644
--- a/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
@@ -79,6 +79,7 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K,V>,
   private MetricsMap cacheMap;
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
   private MetricRegistry registry;
+  private SolrMetricManager.GaugeWrapper myGauge;
 
   @Override
   public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
@@ -231,6 +232,7 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K,V>,
     statsList.get(0).add(cache.getStats());
     statsList.remove(cache.getStats());
     cache.destroy();
+    if(myGauge != null) myGauge.unregister();
   }
 
   //////////////////////// SolrInfoMBeans methods //////////////////////
@@ -304,7 +306,7 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K,V>,
         }
       }
     });
-    manager.registerGauge(this, registryName, cacheMap, tag, true, scope, getCategory().toString());
+    myGauge = manager.registerGauge(this, registryName, cacheMap, tag, true, scope, getCategory().toString());
   }
 
 
diff --git a/solr/core/src/java/org/apache/solr/search/LFUCache.java b/solr/core/src/java/org/apache/solr/search/LFUCache.java
index 37ef4c6..7737454 100644
--- a/solr/core/src/java/org/apache/solr/search/LFUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/LFUCache.java
@@ -86,6 +86,7 @@ public class LFUCache<K, V> implements SolrCache<K, V>, Accountable {
   private int initialSize;
   private int acceptableSize;
   private boolean cleanupThread;
+  private SolrMetricManager.GaugeWrapper myGauge;
 
   @Override
   public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
@@ -227,6 +228,7 @@ public class LFUCache<K, V> implements SolrCache<K, V>, Accountable {
     statsList.get(0).add(cache.getStats());
     statsList.remove(cache.getStats());
     cache.destroy();
+    if(myGauge != null) myGauge.unregister();
   }
 
   //////////////////////// SolrInfoMBeans methods //////////////////////
@@ -311,7 +313,7 @@ public class LFUCache<K, V> implements SolrCache<K, V>, Accountable {
 
       }
     });
-    manager.registerGauge(this, registryName, cacheMap, tag, true, scope, getCategory().toString());
+    myGauge = manager.registerGauge(this, registryName, cacheMap, tag, true, scope, getCategory().toString());
   }
 
   // for unit tests only
diff --git a/solr/core/src/java/org/apache/solr/search/LRUCache.java b/solr/core/src/java/org/apache/solr/search/LRUCache.java
index 3bd5f00..444c549 100644
--- a/solr/core/src/java/org/apache/solr/search/LRUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/LRUCache.java
@@ -47,6 +47,7 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(LRUCache.class);
+  private SolrMetricManager.GaugeWrapper myGauge;
 
   /* An instance of this class will be shared across multiple instances
    * of an LRUCache at the same time.  Make sure everything is thread safe.
@@ -286,6 +287,7 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
 
   @Override
   public void close() {
+    if(myGauge != null) myGauge.unregister();
 
   }
 
@@ -334,7 +336,7 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
       res.put("cumulative_evictions", stats.evictions.longValue());
       res.put("cumulative_evictionsRamUsage", stats.evictionsRamUsage.longValue());
     });
-    manager.registerGauge(this, registryName, cacheMap, tag, true, scope, getCategory().toString());
+    myGauge = manager.registerGauge(this, registryName, cacheMap, tag, true, scope, getCategory().toString());
   }
 
   // for unit tests only
diff --git a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
index b2647cd..0588380 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
@@ -37,6 +37,7 @@ public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
 
   private MetricRegistry registry;
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
+  private SolrMetricManager.GaugeWrapper myGauge;
 
   @Override
   public String getName() { return this.getClass().getName(); }
@@ -72,6 +73,11 @@ public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
         map.put("entries_count", UninvertingReader.getUninvertedStatsSize());
       }
     });
-    manager.registerGauge(this, registryName, metricsMap, tag, true, "fieldCache", Category.CACHE.toString(), scope);
+    myGauge = manager.registerGauge(this, registryName, metricsMap, tag, true, "fieldCache", Category.CACHE.toString(), scope);
+  }
+
+  @Override
+  public void close() throws Exception {
+    if (myGauge != null) myGauge.unregister();
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
index deb6dc1..be5221a 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -120,6 +120,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
   private final SolrCache<Query,DocSet> filterCache;
   private final SolrCache<QueryResultKey,DocList> queryResultCache;
   private final SolrCache<String,UnInvertedField> fieldValueCache;
+  private final List<SolrMetricManager.GaugeWrapper> myGauges = new ArrayList<>();
 
   // map of generic caches - not synchronized since it's read-only after the constructor.
   private final Map<String,SolrCache> cacheMap;
@@ -480,6 +481,10 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
 
     // do this at the end so it only gets done if there are no exceptions
     numCloses.incrementAndGet();
+    for (SolrMetricManager.GaugeWrapper gauge : myGauges) {
+      gauge.unregister();
+    }
+    myGauges.clear();
     assert ObjectReleaseTracker.release(this);
   }
 
@@ -2270,20 +2275,20 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
   public void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
     this.registryName = registry;
     this.metricManager = manager;
-    manager.registerGauge(this, registry, () -> name, tag, true, "searcherName", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> cachingEnabled, tag, true, "caching", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> openTime, tag, true, "openedAt", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> warmupTime, tag, true, "warmupTime", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> registerTime, tag, true, "registeredAt", Category.SEARCHER.toString(), scope);
+    myGauges.add(manager.registerGauge(this, registry, () -> name, tag, true, "searcherName", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> cachingEnabled, tag, true, "caching", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> openTime, tag, true, "openedAt", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> warmupTime, tag, true, "warmupTime", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> registerTime, tag, true, "registeredAt", Category.SEARCHER.toString(), scope));
     // reader stats
-    manager.registerGauge(this, registry, () -> reader.numDocs(), tag, true, "numDocs", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.maxDoc(), tag, true, "maxDoc", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.maxDoc() - reader.numDocs(), tag, true, "deletedDocs", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.toString(), tag, true, "reader", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.directory().toString(), tag, true, "readerDir", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.getVersion(), tag, true, "indexVersion", Category.SEARCHER.toString(), scope);
+    myGauges.add(manager.registerGauge(this, registry, () -> reader.numDocs(), tag, true, "numDocs", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> reader.maxDoc(), tag, true, "maxDoc", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> reader.maxDoc() - reader.numDocs(), tag, true, "deletedDocs", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> reader.toString(), tag, true, "reader", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> reader.directory().toString(), tag, true, "readerDir", Category.SEARCHER.toString(), scope));
+    myGauges.add(manager.registerGauge(this, registry, () -> reader.getVersion(), tag, true, "indexVersion", Category.SEARCHER.toString(), scope));
     // size of the currently opened commit
-    manager.registerGauge(this, registry, () -> {
+    myGauges.add(manager.registerGauge(this, registry, () -> {
       try {
         Collection<String> files = reader.getIndexCommit().getFileNames();
         long total = 0;
@@ -2294,7 +2299,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       } catch (Exception e) {
         return -1;
       }
-    }, tag, true, "indexCommitSize", Category.SEARCHER.toString(), scope);
+    }, tag, true, "indexCommitSize", Category.SEARCHER.toString(), scope));
 
   }
 
diff --git a/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java
index 5fd18a1..1d90762 100644
--- a/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java
@@ -41,7 +41,7 @@ import org.eclipse.jetty.client.api.Request;
  * 
  * @lucene.experimental
  */
-public abstract class AuthenticationPlugin implements Closeable, SolrInfoBean, SolrMetricProducer {
+public abstract class AuthenticationPlugin implements AutoCloseable, SolrInfoBean, SolrMetricProducer {
 
   final public static String AUTHENTICATION_PLUGIN_PROP = "authenticationPlugin";
   final public static String HTTP_HEADER_X_SOLR_AUTHDATA = "X-Solr-AuthData";
diff --git a/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java b/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
index 6d9e9ea..bb77a03 100644
--- a/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
+++ b/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
@@ -56,14 +56,11 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
   private MetricsMap metricsMap;
   private MetricRegistry registry;
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
-  private SolrMetricManager metricManager;
-  private String registryName;
   private long previous = System.nanoTime();
+  private SolrMetricManager.GaugeWrapper myGauge;
 
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registryName, String tag, String scope) {
-    this.metricManager = manager;
-    this.registryName = registryName;
     registry = manager.registry(registryName);
     metricsMap = new MetricsMap((detailed, map) -> {
       long now = System.nanoTime();
@@ -108,7 +105,7 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
       previous = now;
 
     });
-    manager.registerGauge(this, registryName, metricsMap, tag, true, getName(), getCategory().toString(), scope);
+    myGauge = manager.registerGauge(this, registryName, metricsMap, tag, true, getName(), getCategory().toString(), scope);
   }
 
   private float getPerSecond(long value, double seconds) {
@@ -137,4 +134,8 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
     return registry;
   }
 
+  @Override
+  public void close() {
+    if(myGauge!= null) myGauge.unregister();
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java b/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java
index 2bf60cb..50411a6 100644
--- a/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java
+++ b/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java
@@ -52,8 +52,7 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
 
   private final Set<String> metricNames = ConcurrentHashMap.newKeySet();
   private MetricRegistry registry;
-  private SolrMetricManager metricManager;
-  private String registryName;
+  private SolrMetricManager.GaugeWrapper myGauge;
 
   public HdfsLocalityReporter() {
     cache = new ConcurrentHashMap<>();
@@ -97,8 +96,6 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
    */
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registryName, String tag, String scope) {
-    this.metricManager = manager;
-    this.registryName = registryName;
     registry = manager.registry(registryName);
     MetricsMap metricsMap = new MetricsMap((detailed, map) -> {
       long totalBytes = 0;
@@ -149,7 +146,7 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
         map.put(LOCALITY_BLOCKS_RATIO, localCount / (double) totalCount);
       }
     });
-    manager.registerGauge(this, registryName, metricsMap, tag, true, "hdfsLocality", getCategory().toString(), scope);
+    myGauge = manager.registerGauge(this, registryName, metricsMap, tag, true, "hdfsLocality", getCategory().toString(), scope);
   }
 
   /**
@@ -195,4 +192,8 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
     }
   }
 
+  @Override
+  public void close() throws Exception {
+    if (myGauge != null) myGauge.unregister();
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java b/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java
index 538a983..99f0b52 100644
--- a/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java
+++ b/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java
@@ -18,6 +18,7 @@ package org.apache.solr.update;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -92,6 +93,7 @@ public class SolrIndexWriter extends IndexWriter {
   private final String registryName;
   // merge diagnostics.
   private final Map<String, Long> runningMerges = new ConcurrentHashMap<>();
+  private final ArrayList<SolrMetricManager.GaugeWrapper> myGauges = new ArrayList<>();
 
   public static SolrIndexWriter create(SolrCore core, String name, String path, DirectoryFactory directoryFactory, boolean create, IndexSchema schema, SolrIndexConfig config, IndexDeletionPolicy delPolicy, Codec codec) throws IOException {
 
@@ -168,12 +170,12 @@ public class SolrIndexWriter extends IndexWriter {
         majorMerge = metricManager.timer(null, registryName, "major", SolrInfoBean.Category.INDEX.toString(), "merge");
         mergeErrors = metricManager.counter(null, registryName, "errors", SolrInfoBean.Category.INDEX.toString(), "merge");
         String tag = core.getMetricTag();
-        metricManager.registerGauge(null, registryName, () -> runningMajorMerges.get(), tag, true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
-        metricManager.registerGauge(null, registryName, () -> runningMinorMerges.get(), tag, true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
-        metricManager.registerGauge(null, registryName, () -> runningMajorMergesDocs.get(), tag, true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
-        metricManager.registerGauge(null, registryName, () -> runningMinorMergesDocs.get(), tag, true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
-        metricManager.registerGauge(null, registryName, () -> runningMajorMergesSegments.get(), tag, true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
-        metricManager.registerGauge(null, registryName, () -> runningMinorMergesSegments.get(), tag, true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
+        myGauges.add(metricManager.registerGauge(null, registryName, () -> runningMajorMerges.get(), tag, true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "major"));
+        myGauges.add(metricManager.registerGauge(null, registryName, () -> runningMinorMerges.get(), tag, true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "minor"));
+        myGauges.add(metricManager.registerGauge(null, registryName, () -> runningMajorMergesDocs.get(), tag, true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "major"));
+        myGauges.add(metricManager.registerGauge(null, registryName, () -> runningMinorMergesDocs.get(), tag, true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "minor"));
+        myGauges.add(metricManager.registerGauge(null, registryName, () -> runningMajorMergesSegments.get(), tag, true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "major"));
+        myGauges.add(metricManager.registerGauge(null, registryName, () -> runningMinorMergesSegments.get(), tag, true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "minor"));
         flushMeter = metricManager.meter(null, registryName, "flush", SolrInfoBean.Category.INDEX.toString());
       }
     }
@@ -305,6 +307,10 @@ public class SolrIndexWriter extends IndexWriter {
       }
       log.error("Error closing IndexWriter", t);
     } finally {
+      for (SolrMetricManager.GaugeWrapper gauge : myGauges) {
+        gauge.unregister();
+      }
+      myGauges.clear();
       cleanup();
     }
   }
@@ -348,4 +354,5 @@ public class SolrIndexWriter extends IndexWriter {
     }
   }
 
+
 }
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateLog.java b/solr/core/src/java/org/apache/solr/update/UpdateLog.java
index 612bc6e..56252ca 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateLog.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateLog.java
@@ -102,6 +102,8 @@ public class UpdateLog implements PluginInfoInitialized, SolrMetricProducer {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   private boolean debug = log.isDebugEnabled();
   private boolean trace = log.isTraceEnabled();
+  private final List<SolrMetricManager.GaugeWrapper> myGauges = new ArrayList<>();
+
 
   // TODO: hack
   public FileSystem getFs() {
@@ -451,13 +453,13 @@ public class UpdateLog implements PluginInfoInitialized, SolrMetricProducer {
       }
     };
 
-    manager.registerGauge(null, registry, bufferedOpsGauge, tag, true, "ops", scope, "buffered");
-    manager.registerGauge(null, registry, () -> logs.size(), tag, true, "logs", scope, "replay", "remaining");
-    manager.registerGauge(null, registry, () -> getTotalLogsSize(), tag, true, "bytes", scope, "replay", "remaining");
+    myGauges.add(manager.registerGauge(null, registry, bufferedOpsGauge, tag, true, "ops", scope, "buffered"));
+    myGauges.add(manager.registerGauge(null, registry, () -> logs.size(), tag, true, "logs", scope, "replay", "remaining"));
+    myGauges.add(manager.registerGauge(null, registry, () -> getTotalLogsSize(), tag, true, "bytes", scope, "replay", "remaining"));
     applyingBufferedOpsMeter = manager.meter(null, registry, "ops", scope, "applyingBuffered");
     replayOpsMeter = manager.meter(null, registry, "ops", scope, "replay");
     copyOverOldUpdatesMeter = manager.meter(null, registry, "ops", scope, "copyOverOldUpdates");
-    manager.registerGauge(null, registry, () -> state.getValue(), tag, true, "state", scope);
+    myGauges.add(manager.registerGauge(null, registry, () -> state.getValue(), tag, true, "state", scope));
   }
 
   /**
@@ -1383,6 +1385,13 @@ public class UpdateLog implements PluginInfoInitialized, SolrMetricProducer {
     }
   }
 
+  @Override
+  public void close() {
+    for (SolrMetricManager.GaugeWrapper gauge : myGauges) {
+      gauge.unregister();
+    }
+    myGauges.clear();
+  }
 
   static class Update {
     TransactionLog log;
diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingHttpClientConnectionManager.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingHttpClientConnectionManager.java
index 398ab8b..6c24b5d 100644
--- a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingHttpClientConnectionManager.java
+++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingHttpClientConnectionManager.java
@@ -17,6 +17,8 @@
 
 package org.apache.solr.util.stats;
 
+import java.util.ArrayList;
+
 import org.apache.http.config.Registry;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
@@ -31,6 +33,7 @@ public class InstrumentedPoolingHttpClientConnectionManager extends PoolingHttpC
 
   private SolrMetricManager metricManager;
   private String registryName;
+  private final ArrayList<SolrMetricManager.GaugeWrapper> myGauges = new ArrayList<>() ;
 
   public InstrumentedPoolingHttpClientConnectionManager(Registry<ConnectionSocketFactory> socketFactoryRegistry) {
     super(socketFactoryRegistry);
@@ -40,14 +43,23 @@ public class InstrumentedPoolingHttpClientConnectionManager extends PoolingHttpC
   public void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
     this.metricManager = manager;
     this.registryName = registry;
-    manager.registerGauge(null, registry, () -> getTotalStats().getAvailable(),
-        tag, true, SolrMetricManager.mkName("availableConnections", scope));
+    myGauges.add(manager.registerGauge(null, registry, () -> getTotalStats().getAvailable(),
+        tag, true, SolrMetricManager.mkName("availableConnections", scope)));
     // this acquires a lock on the connection pool; remove if contention sucks
-    manager.registerGauge(null, registry, () -> getTotalStats().getLeased(),
-        tag, true, SolrMetricManager.mkName("leasedConnections", scope));
-    manager.registerGauge(null, registry, () -> getTotalStats().getMax(),
-        tag, true, SolrMetricManager.mkName("maxConnections", scope));
-    manager.registerGauge(null, registry, () -> getTotalStats().getPending(),
-        tag, true, SolrMetricManager.mkName("pendingConnections", scope));
+    myGauges.add(manager.registerGauge(null, registry, () -> getTotalStats().getLeased(),
+        tag, true, SolrMetricManager.mkName("leasedConnections", scope)));
+    myGauges.add(manager.registerGauge(null, registry, () -> getTotalStats().getMax(),
+        tag, true, SolrMetricManager.mkName("maxConnections", scope)));
+    myGauges.add(manager.registerGauge(null, registry, () -> getTotalStats().getPending(),
+        tag, true, SolrMetricManager.mkName("pendingConnections", scope)));
+  }
+
+  @Override
+  public void close() {
+    super.close();
+    for (SolrMetricManager.GaugeWrapper gauge : myGauges) {
+      gauge.unregister();
+    }
+    myGauges.clear();
   }
 }