SOLR-14252: NullPointerException in AggregateMetric.

This commit is contained in:
Andrzej Bialecki 2020-02-27 12:58:57 +01:00
parent 0e0aa6e207
commit ad9b2d2e19
4 changed files with 61 additions and 19 deletions

View File

@ -152,6 +152,8 @@ Bug Fixes
* SOLR-14250: Do not log error when trying to consume non-existing input stream due to Expect: 100-continue (janhoy) * SOLR-14250: Do not log error when trying to consume non-existing input stream due to Expect: 100-continue (janhoy)
* SOLR-14252: Avoid NullPointerException in AggregateMetric. (Andy Webb via ab)
Other Changes Other Changes
--------------------- ---------------------

View File

@ -107,6 +107,9 @@ public class AggregateMetric implements Metric {
res = n.doubleValue(); res = n.doubleValue();
} }
} }
if (res == null) {
return 0;
}
return res; return res;
} }
@ -128,6 +131,9 @@ public class AggregateMetric implements Metric {
res = n.doubleValue(); res = n.doubleValue();
} }
} }
if (res == null) {
return 0;
}
return res; return res;
} }

View File

@ -79,11 +79,23 @@ public class MetricUtilsTest extends SolrTestCaseJ4 {
meter.mark(); meter.mark();
Histogram histogram = registry.histogram("histogram"); Histogram histogram = registry.histogram("histogram");
histogram.update(10); histogram.update(10);
AggregateMetric am = new AggregateMetric();
registry.register("aggregate", am); // SOLR-14252: check that negative values are supported correctly
am.set("foo", 10); // NB a-d represent the same metric from multiple nodes
am.set("bar", 1); AggregateMetric am1 = new AggregateMetric();
am.set("bar", 2); registry.register("aggregate1", am1);
am1.set("a", -10);
am1.set("b", 1);
am1.set("b", -2);
am1.set("c", -3);
am1.set("d", -5);
// SOLR-14252: check that aggregation of non-Number metrics don't trigger NullPointerException
AggregateMetric am2 = new AggregateMetric();
registry.register("aggregate2", am2);
am2.set("a", false);
am2.set("b", true);
Gauge<String> gauge = () -> "foobar"; Gauge<String> gauge = () -> "foobar";
registry.register("gauge", gauge); registry.register("gauge", gauge);
Gauge<Long> error = () -> {throw new InternalError("Memory Pool not found error");}; Gauge<Long> error = () -> {throw new InternalError("Memory Pool not found error");};
@ -102,17 +114,26 @@ public class MetricUtilsTest extends SolrTestCaseJ4 {
assertEquals(1L, v.get("count")); assertEquals(1L, v.get("count"));
} else if (k.startsWith("histogram")) { } else if (k.startsWith("histogram")) {
assertEquals(1L, v.get("count")); assertEquals(1L, v.get("count"));
} else if (k.startsWith("aggregate")) { } else if (k.startsWith("aggregate1")) {
assertEquals(2, v.get("count")); assertEquals(4, v.get("count"));
Map<String, Object> values = (Map<String, Object>)v.get("values"); Map<String, Object> values = (Map<String, Object>)v.get("values");
assertNotNull(values); assertNotNull(values);
assertEquals(2, values.size()); assertEquals(4, values.size());
Map<String, Object> update = (Map<String, Object>)values.get("foo"); Map<String, Object> update = (Map<String, Object>)values.get("a");
assertEquals(10, update.get("value")); assertEquals(-10, update.get("value"));
assertEquals(1, update.get("updateCount")); assertEquals(1, update.get("updateCount"));
update = (Map<String, Object>)values.get("bar"); update = (Map<String, Object>)values.get("b");
assertEquals(2, update.get("value")); assertEquals(-2, update.get("value"));
assertEquals(2, update.get("updateCount")); assertEquals(2, update.get("updateCount"));
assertEquals(-10D, v.get("min"));
assertEquals(-2D, v.get("max"));
assertEquals(-5D, v.get("mean"));
} else if (k.startsWith("aggregate2")) {
// SOLR-14252: non-Number metric aggregations should return 0 rather than throwing NPE
assertEquals(2, v.get("count"));
assertEquals(0D, v.get("min"));
assertEquals(0D, v.get("max"));
assertEquals(0D, v.get("mean"));
} else if (k.startsWith("memory.expected.error")) { } else if (k.startsWith("memory.expected.error")) {
assertNull(v); assertNull(v);
} }
@ -139,19 +160,32 @@ public class MetricUtilsTest extends SolrTestCaseJ4 {
assertTrue(o instanceof Map); assertTrue(o instanceof Map);
Map v = (Map)o; Map v = (Map)o;
assertEquals(1L, v.get("count")); assertEquals(1L, v.get("count"));
} else if (k.startsWith("aggregate")) { } else if (k.startsWith("aggregate1")) {
assertTrue(o instanceof Map);
Map v = (Map)o;
assertEquals(4, v.get("count"));
Map<String, Object> values = (Map<String, Object>)v.get("values");
assertNotNull(values);
assertEquals(4, values.size());
Map<String, Object> update = (Map<String, Object>)values.get("a");
assertEquals(-10, update.get("value"));
assertEquals(1, update.get("updateCount"));
update = (Map<String, Object>)values.get("b");
assertEquals(-2, update.get("value"));
assertEquals(2, update.get("updateCount"));
} else if (k.startsWith("aggregate2")) {
assertTrue(o instanceof Map); assertTrue(o instanceof Map);
Map v = (Map)o; Map v = (Map)o;
assertEquals(2, v.get("count")); assertEquals(2, v.get("count"));
Map<String, Object> values = (Map<String, Object>)v.get("values"); Map<String, Object> values = (Map<String, Object>)v.get("values");
assertNotNull(values); assertNotNull(values);
assertEquals(2, values.size()); assertEquals(2, values.size());
Map<String, Object> update = (Map<String, Object>)values.get("foo"); Map<String, Object> update = (Map<String, Object>)values.get("a");
assertEquals(10, update.get("value")); assertEquals(false, update.get("value"));
assertEquals(1, update.get("updateCount"));
update = (Map<String, Object>)values.get("b");
assertEquals(true, update.get("value"));
assertEquals(1, update.get("updateCount")); assertEquals(1, update.get("updateCount"));
update = (Map<String, Object>)values.get("bar");
assertEquals(2, update.get("value"));
assertEquals(2, update.get("updateCount"));
} else if (k.startsWith("memory.expected.error")) { } else if (k.startsWith("memory.expected.error")) {
assertNull(o); assertNull(o);
} else { } else {

View File

@ -519,7 +519,7 @@ Example configuration:
</lst> </lst>
<lst name="report"> <lst name="report">
<str name="group">aggregated_shard_leaders</str> <str name="group">aggregated_shard_leaders</str>
<str name="registry">solr\.core\.(.*)\.leader</str> <str name="registry">solr\.collection\.(.*)\.leader</str>
<str name="label">leader.$1</str> <str name="label">leader.$1</str>
<str name="filter">UPDATE\./update/.*</str> <str name="filter">UPDATE\./update/.*</str>
</lst> </lst>