Skip to content

Commit 28a2ee2

Browse files
authored
SOLR-17777: Fix leaked metric registry after core unload (#3382)
This fixes a minor memory leak when deleting a core. I don't think it can have a significant impact on heap, but the fix is trivial and not risky.
1 parent cda6c8c commit 28a2ee2

5 files changed

Lines changed: 62 additions & 5 deletions

File tree

solr/CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ Bug Fixes
339339

340340
* SOLR-17711: Remove total request timeout during recovery that was inadvertently added. (Luke Kot-Zaniewski)
341341

342+
* SOLR-17777: Fix a very minor memory leak in metrics reporting code when a core is deleted. (Pierre Salagnac)
343+
342344
Dependency Upgrades
343345
---------------------
344346
* SOLR-17471: Upgrade Lucene to 9.12.1. (Pierre Salagnac, Christine Poerschke)

solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,19 +448,35 @@ private static boolean isSharedRegistry(String registry) {
448448
}
449449

450450
/**
451-
* Get (or create if not present) a named registry
451+
* Get (or create if not present) a named registry. This method always creates and persists a new
452+
* registry in case it does not already exist.
452453
*
453454
* @param registry name of the registry
454455
* @return existing or newly created registry
455456
*/
456457
public MetricRegistry registry(String registry) {
458+
return registry(registry, true);
459+
}
460+
461+
/**
462+
* Get (or create if not present) a named registry.
463+
*
464+
* @param registry name of the registry.
465+
* @param create When false and the registry does not exist, we return null instead of creating a
466+
* new one.
467+
*/
468+
public MetricRegistry registry(String registry, boolean create) {
457469
registry = enforcePrefix(registry);
458470
if (isSharedRegistry(registry)) {
459471
return SharedMetricRegistries.getOrCreate(registry);
460472
} else {
461473
swapLock.lock();
462474
try {
463-
return getOrCreateRegistry(registries, registry);
475+
if (create) {
476+
return getOrCreateRegistry(registries, registry);
477+
} else {
478+
return registries.get(registry);
479+
}
464480
} finally {
465481
swapLock.unlock();
466482
}
@@ -830,7 +846,7 @@ public int unregisterGauges(String registryName, String tagSegment) {
830846
if (tagSegment == null) {
831847
return 0;
832848
}
833-
MetricRegistry registry = registry(registryName);
849+
MetricRegistry registry = registry(registryName, false);
834850
if (registry == null) return 0;
835851
AtomicInteger removed = new AtomicInteger();
836852
registry.removeMatching(

solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ public void test() throws Exception {
199199

200200
// check replication metrics on this jetty - see SOLR-14924
201201
for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
202-
if (jetty.getCoreContainer() == null) {
202+
if (emptyNode.equals(jetty.getNodeName())) {
203+
// No cores on this node, ignore it
203204
continue;
204205
}
205206
SolrMetricManager metricManager = jetty.getCoreContainer().getMetricManager();

solr/core/src/test/org/apache/solr/cloud/ReplaceNodeTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ public void test() throws Exception {
179179

180180
// check replication metrics on this jetty - see SOLR-14924
181181
for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
182-
if (jetty.getCoreContainer() == null) {
182+
if (emptyNode.equals(jetty.getNodeName())) {
183+
// No cores on this node, ignore it
183184
continue;
184185
}
185186
SolrMetricManager metricManager = jetty.getCoreContainer().getMetricManager();

solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,22 @@
2323
import java.util.HashMap;
2424
import java.util.Map;
2525
import java.util.Random;
26+
import java.util.Set;
2627
import java.util.stream.Collectors;
2728
import org.apache.lucene.tests.util.TestUtil;
2829
import org.apache.solr.SolrTestCaseJ4;
2930
import org.apache.solr.common.params.CoreAdminParams;
31+
import org.apache.solr.common.params.MapSolrParams;
32+
import org.apache.solr.common.params.SolrParams;
33+
import org.apache.solr.common.params.UpdateParams;
34+
import org.apache.solr.core.CoreContainer;
3035
import org.apache.solr.core.PluginInfo;
36+
import org.apache.solr.core.SolrCore;
3137
import org.apache.solr.core.SolrInfoBean;
3238
import org.apache.solr.metrics.reporters.MockMetricReporter;
39+
import org.apache.solr.request.SolrQueryRequestBase;
3340
import org.apache.solr.schema.FieldType;
41+
import org.apache.solr.update.CommitUpdateCommand;
3442
import org.junit.After;
3543
import org.junit.Before;
3644
import org.junit.Test;
@@ -177,4 +185,33 @@ public void testNonCloudRegistryName() {
177185
assertEquals("solr.core.collection1", registryName);
178186
assertNull(leaderRegistryName);
179187
}
188+
189+
/** Check the metric registry specific to a core is removed once the core is unloaded. */
190+
@Test
191+
public void testNoRegistryAfterUnload() throws Exception {
192+
193+
String coreRegistryName;
194+
195+
CoreContainer cc = h.getCoreContainer();
196+
SolrMetricManager metricManager = cc.getMetricManager();
197+
198+
SolrCore core = cc.create("to-unload", Map.of("configSet", "minimal"));
199+
coreRegistryName = core.getSolrMetricsContext().getRegistryName();
200+
201+
Set<String> names = metricManager.registryNames();
202+
assertTrue("missing registry", names.contains(coreRegistryName));
203+
204+
// Commit and wait for searcher to ensure the searcher is created. This is required to make sure
205+
// the core inner thread does not create it *after* we asked the container to unload the core.
206+
SolrParams params = new MapSolrParams(Map.of(UpdateParams.WAIT_SEARCHER, "true"));
207+
core.getUpdateHandler()
208+
.commit(new CommitUpdateCommand(new SolrQueryRequestBase(h.getCore(), params) {}, false));
209+
210+
cc.unload("to-unload");
211+
212+
// Make sure the core metric registry does not exist anymore once we fully removed the core
213+
// from the container
214+
names = metricManager.registryNames();
215+
assertFalse(names.contains(coreRegistryName));
216+
}
180217
}

0 commit comments

Comments
 (0)