From 137a562b02d958ce3591a59580117c103df45004 Mon Sep 17 00:00:00 2001 From: Ignacio Vera Date: Mon, 24 Nov 2025 08:14:25 +0100 Subject: [PATCH] Break on FieldData when building global ordinals (#108875) This commit adds the bytes and break if we get over the limit of the breaker when building global ordinals. --- docs/changelog/108875.yaml | 6 ++++++ .../ordinals/GlobalOrdinalsBuilder.java | 2 +- .../index/fielddata/FieldDataCacheTests.java | 18 +++++++++++++----- 3 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 docs/changelog/108875.yaml diff --git a/docs/changelog/108875.yaml b/docs/changelog/108875.yaml new file mode 100644 index 0000000000000..0d6ce38dcb536 --- /dev/null +++ b/docs/changelog/108875.yaml @@ -0,0 +1,6 @@ +pr: 108875 +summary: Break on `FieldData` when building global ordinals +area: Aggregations +type: bug +issues: + - 97075 diff --git a/server/src/main/java/org/elasticsearch/index/fielddata/ordinals/GlobalOrdinalsBuilder.java b/server/src/main/java/org/elasticsearch/index/fielddata/ordinals/GlobalOrdinalsBuilder.java index def1c40e1e6f0..7ce851f5bdafa 100644 --- a/server/src/main/java/org/elasticsearch/index/fielddata/ordinals/GlobalOrdinalsBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/fielddata/ordinals/GlobalOrdinalsBuilder.java @@ -72,7 +72,7 @@ public BytesRef next() throws IOException { } final OrdinalMap ordinalMap = OrdinalMap.build(null, termsEnums, weights, PackedInts.DEFAULT); final long memorySizeInBytes = ordinalMap.ramBytesUsed(); - breaker.addWithoutBreaking(memorySizeInBytes); + breaker.addEstimateBytesAndMaybeBreak(memorySizeInBytes, "Global Ordinals"); TimeValue took = new TimeValue(System.nanoTime() - startTimeNS, TimeUnit.NANOSECONDS); if (logger.isDebugEnabled()) { diff --git a/server/src/test/java/org/elasticsearch/index/fielddata/FieldDataCacheTests.java b/server/src/test/java/org/elasticsearch/index/fielddata/FieldDataCacheTests.java index 67ef6ad7778e5..1080bd5235e92 100644 --- a/server/src/test/java/org/elasticsearch/index/fielddata/FieldDataCacheTests.java +++ b/server/src/test/java/org/elasticsearch/index/fielddata/FieldDataCacheTests.java @@ -37,6 +37,7 @@ import org.elasticsearch.test.FieldMaskingReader; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; public class FieldDataCacheTests extends ESTestCase { private static final ToScriptFieldFactory MOCK_TO_SCRIPT_FIELD = (dv, n) -> new DelegateDocValuesField( @@ -100,7 +101,8 @@ public void testGlobalOrdinalsCircuitBreaker() throws Exception { iw.close(); DirectoryReader ir = ElasticsearchDirectoryReader.wrap(DirectoryReader.open(dir), new ShardId("_index", "_na_", 0)); - int[] timesCalled = new int[1]; + int[] timesCalledForParent = new int[1]; + long[] timesCalledForFieldData = new long[1]; SortedSetOrdinalsIndexFieldData sortedSetOrdinalsIndexFieldData = new SortedSetOrdinalsIndexFieldData( new DummyAccountingFieldDataCache(), "field1", @@ -113,16 +115,22 @@ public CircuitBreaker getBreaker(String name) { @Override public void addEstimateBytesAndMaybeBreak(long bytes, String label) throws CircuitBreakingException { assertThat(label, equalTo("Global Ordinals")); - assertThat(bytes, equalTo(0L)); - timesCalled[0]++; + if (bytes == 0) { + timesCalledForParent[0]++; + } else { + assertThat(timesCalledForFieldData[0], equalTo(0L)); + assertThat(bytes, greaterThan(0L)); + timesCalledForFieldData[0] = bytes; + } } }; } }, MOCK_TO_SCRIPT_FIELD ); - sortedSetOrdinalsIndexFieldData.loadGlobal(ir); - assertThat(timesCalled[0], equalTo(2)); + IndexOrdinalsFieldData globalOrdinals = sortedSetOrdinalsIndexFieldData.loadGlobal(ir); + assertThat(timesCalledForParent[0], equalTo(2)); + assertThat(timesCalledForFieldData[0], equalTo(globalOrdinals.getOrdinalMap().ramBytesUsed())); ir.close(); dir.close();