This is an automated email from the ASF dual-hosted git repository. epugh pushed a commit to branch branch_9_11 in repository https://gitbox.apache.org/repos/asf/solr.git
commit 95a38dc47f915f2d1e904d3581a4aee1b5e35619 Author: Jalaz Kumar <[email protected]> AuthorDate: Sat May 16 00:15:57 2026 +0530 SOLR-18239: Fixed NPE during size estimator calculations (#4427) Co-authored-by: Eric Pugh <[email protected]> (cherry picked from commit b7aeda98b8477ea12a61f979344054e20fd0b342) (cherry picked from commit ea61a9953329b42ac1ecd27461d84454feefa336) --- .../SOLR-18239-fix-npe-size-estimator.yml | 7 ++++ .../IgnoreLargeDocumentProcessorFactory.java | 1 + .../IgnoreLargeDocumentProcessorFactoryTest.java | 10 ++++-- .../update/processor/MirroringUpdateProcessor.java | 1 + .../processor/MirroringUpdateProcessorTest.java | 37 ++++++++++++++++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) diff --git a/changelog/unreleased/SOLR-18239-fix-npe-size-estimator.yml b/changelog/unreleased/SOLR-18239-fix-npe-size-estimator.yml new file mode 100644 index 00000000000..05b9993b452 --- /dev/null +++ b/changelog/unreleased/SOLR-18239-fix-npe-size-estimator.yml @@ -0,0 +1,7 @@ +title: Fixed NPE in size estimator for null valued fields +type: fixed +authors: + - name: Jalaz Kumar +links: + - name: SOLR-18239 + url: https://issues.apache.org/jira/browse/SOLR-18239 diff --git a/solr/core/src/java/org/apache/solr/update/processor/IgnoreLargeDocumentProcessorFactory.java b/solr/core/src/java/org/apache/solr/update/processor/IgnoreLargeDocumentProcessorFactory.java index 7f9d1c250d9..a86137ce07d 100644 --- a/solr/core/src/java/org/apache/solr/update/processor/IgnoreLargeDocumentProcessorFactory.java +++ b/solr/core/src/java/org/apache/solr/update/processor/IgnoreLargeDocumentProcessorFactory.java @@ -170,6 +170,7 @@ public class IgnoreLargeDocumentProcessorFactory extends UpdateRequestProcessorF } private static long primitiveEstimate(Object obj, long def) { + if (obj == null) return def; Class<?> clazz = obj.getClass(); if (clazz.isPrimitive()) { return primitiveSizes.get(clazz); diff --git a/solr/core/src/test/org/apache/solr/update/processor/IgnoreLargeDocumentProcessorFactoryTest.java b/solr/core/src/test/org/apache/solr/update/processor/IgnoreLargeDocumentProcessorFactoryTest.java index 513b0589157..167aaf14568 100644 --- a/solr/core/src/test/org/apache/solr/update/processor/IgnoreLargeDocumentProcessorFactoryTest.java +++ b/solr/core/src/test/org/apache/solr/update/processor/IgnoreLargeDocumentProcessorFactoryTest.java @@ -86,6 +86,7 @@ public class IgnoreLargeDocumentProcessorFactoryTest extends SolrTestCase { @Test public void testEstimateObjectSize() { + assertEquals(estimate(null), 0); assertEquals(estimate("abc"), 6); assertEquals(estimate("abcdefgh"), 16); List<String> keys = List.of("int", "long", "double", "float", "str"); @@ -99,7 +100,8 @@ public class IgnoreLargeDocumentProcessorFactoryTest extends SolrTestCase { map.put("double", 12.0); map.put("float", 5.0f); map.put("str", "duck"); - assertEquals(estimate(map), 50); + map.put("short", null); + assertEquals(estimate(map), 60); SolrInputDocument document = new SolrInputDocument(); for (Map.Entry<String, Object> entry : map.entrySet()) { @@ -134,7 +136,8 @@ public class IgnoreLargeDocumentProcessorFactoryTest extends SolrTestCase { mapWChild.put("double", 12.0); mapWChild.put("float", 5.0f); mapWChild.put("str", "duck"); - assertEquals(estimate(mapWChild), 50); + mapWChild.put("short", null); + assertEquals(estimate(mapWChild), 60); Map<String, Object> childMap = new HashMap<>(mapWChild); SolrInputDocument document = new SolrInputDocument(); @@ -175,7 +178,8 @@ public class IgnoreLargeDocumentProcessorFactoryTest extends SolrTestCase { mapWChild.put("double", 12.0); mapWChild.put("float", 5.0f); mapWChild.put("str", "duck"); - assertEquals(estimate(mapWChild), 50); + mapWChild.put("short", null); + assertEquals(estimate(mapWChild), 60); Map<String, Object> childMap = new HashMap<>(mapWChild); SolrInputDocument document = new SolrInputDocument(); diff --git a/solr/modules/cross-dc/src/java/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessor.java b/solr/modules/cross-dc/src/java/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessor.java index 3b391f83b83..a78622d27b7 100644 --- a/solr/modules/cross-dc/src/java/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessor.java +++ b/solr/modules/cross-dc/src/java/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessor.java @@ -499,6 +499,7 @@ public class MirroringUpdateProcessor extends UpdateRequestProcessor { } private static long primitiveEstimate(Object obj, long def) { + if (obj == null) return def; Class<?> clazz = obj.getClass(); if (clazz.isPrimitive()) { return primitiveSizes.get(clazz); diff --git a/solr/modules/cross-dc/src/test/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessorTest.java b/solr/modules/cross-dc/src/test/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessorTest.java index a24f8728717..3108eea70b6 100644 --- a/solr/modules/cross-dc/src/test/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessorTest.java +++ b/solr/modules/cross-dc/src/test/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessorTest.java @@ -16,6 +16,7 @@ */ package org.apache.solr.crossdc.update.processor; +import static org.apache.solr.crossdc.update.processor.MirroringUpdateProcessor.ObjectSizeEstimator.estimate; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -26,6 +27,8 @@ import static org.mockito.Mockito.when; import com.codahale.metrics.Counter; import com.codahale.metrics.Histogram; import java.io.IOException; +import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrQuery; @@ -450,6 +453,40 @@ public class MirroringUpdateProcessorTest extends SolrTestCaseJ4 { processor.processDelete(deleteUpdateCommand); } + @Test + public void testEstimateObjectSize() { + assertEquals(estimate(null), 0); + assertEquals(estimate("abc"), 6); + assertEquals(estimate("abcdefgh"), 16); + List<String> keys = List.of("int", "long", "double", "float", "str"); + assertEquals(estimate(keys), 42); + List<Object> values = List.of(12, 5L, 12.0, 5.0, "duck"); + assertEquals(estimate(values), 8); + + Map<String, Object> map = new HashMap<>(); + map.put("int", 12); + map.put("long", 5L); + map.put("double", 12.0); + map.put("float", 5.0f); + map.put("str", "duck"); + map.put("short", null); + assertEquals(estimate(map), 60); + + SolrInputDocument document = new SolrInputDocument(); + for (Map.Entry<String, Object> entry : map.entrySet()) { + document.addField(entry.getKey(), entry.getValue()); + } + assertEquals(MirroringUpdateProcessor.ObjectSizeEstimator.estimate(document), estimate(map)); + + SolrInputDocument childDocument = new SolrInputDocument(); + for (Map.Entry<String, Object> entry : map.entrySet()) { + childDocument.addField(entry.getKey(), entry.getValue()); + } + document.addChildDocument(childDocument); + assertEquals( + MirroringUpdateProcessor.ObjectSizeEstimator.estimate(document), estimate(map) * 2); + } + @Test public void testFinish() throws IOException { processor.finish();
