From 7f1306f1b725bd5d73587a317b4f8c93e5ca4cfe Mon Sep 17 00:00:00 2001 From: Alan Woodward Date: Mon, 13 Jul 2026 15:54:39 +0100 Subject: [PATCH 1/2] Don't throw IOException from PointValues metadata methods Metadata is loaded at segment open time and doesn't require any IO to load once the IndexReader is available. Stop throwing IOException from these methods. --- .../simpletext/SimpleTextBKDReader.java | 6 +- .../lucene/index/ExitableDirectoryReader.java | 10 +- .../org/apache/lucene/index/PointValues.java | 18 +-- .../lucene/index/PointValuesWriter.java | 12 +- .../SlowCompositeCodecReaderWrapper.java | 111 ++++++++---------- .../lucene/index/SortingCodecReader.java | 10 +- .../org/apache/lucene/util/bkd/BKDReader.java | 6 +- .../lucene/index/TestIndexWriterReader.java | 13 +- .../lucene/util/TestDocIdSetBuilder.java | 10 +- .../lucene/index/memory/MemoryIndex.java | 10 +- .../codecs/cranky/CrankyPointsFormat.java | 25 +--- .../tests/index/AssertingLeafReader.java | 10 +- .../tests/index/BasePointsFormatTestCase.java | 10 +- 13 files changed, 110 insertions(+), 141 deletions(-) diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextBKDReader.java b/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextBKDReader.java index 3c574375443e..6ba536669376 100644 --- a/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextBKDReader.java +++ b/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextBKDReader.java @@ -444,17 +444,17 @@ public byte[] getMaxPackedValue() { } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { return config.numDims(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { return config.numIndexDims(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { return config.bytesPerDim(); } diff --git a/lucene/core/src/java/org/apache/lucene/index/ExitableDirectoryReader.java b/lucene/core/src/java/org/apache/lucene/index/ExitableDirectoryReader.java index 42eb41b0dcaa..ef58d3d1136c 100644 --- a/lucene/core/src/java/org/apache/lucene/index/ExitableDirectoryReader.java +++ b/lucene/core/src/java/org/apache/lucene/index/ExitableDirectoryReader.java @@ -646,31 +646,31 @@ public PointTree getPointTree() throws IOException { } @Override - public byte[] getMinPackedValue() throws IOException { + public byte[] getMinPackedValue() { checkAndThrow(); return in.getMinPackedValue(); } @Override - public byte[] getMaxPackedValue() throws IOException { + public byte[] getMaxPackedValue() { checkAndThrow(); return in.getMaxPackedValue(); } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { checkAndThrow(); return in.getNumDimensions(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { checkAndThrow(); return in.getNumIndexDimensions(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { checkAndThrow(); return in.getBytesPerDimension(); } diff --git a/lucene/core/src/java/org/apache/lucene/index/PointValues.java b/lucene/core/src/java/org/apache/lucene/index/PointValues.java index 328bdedb0574..d795a8c3a31d 100644 --- a/lucene/core/src/java/org/apache/lucene/index/PointValues.java +++ b/lucene/core/src/java/org/apache/lucene/index/PointValues.java @@ -118,7 +118,7 @@ public abstract class PointValues { * * @see PointValues#size() */ - public static long size(IndexReader reader, String field) throws IOException { + public static long size(IndexReader reader, String field) { long size = 0; for (LeafReaderContext ctx : reader.leaves()) { PointValues values = ctx.reader().getPointValues(field); @@ -135,7 +135,7 @@ public static long size(IndexReader reader, String field) throws IOException { * * @see PointValues#getDocCount() */ - public static int getDocCount(IndexReader reader, String field) throws IOException { + public static int getDocCount(IndexReader reader, String field) { int count = 0; for (LeafReaderContext ctx : reader.leaves()) { PointValues values = ctx.reader().getPointValues(field); @@ -152,7 +152,7 @@ public static int getDocCount(IndexReader reader, String field) throws IOExcepti * * @see PointValues#getMinPackedValue() */ - public static byte[] getMinPackedValue(IndexReader reader, String field) throws IOException { + public static byte[] getMinPackedValue(IndexReader reader, String field) { byte[] minValue = null; for (LeafReaderContext ctx : reader.leaves()) { PointValues values = ctx.reader().getPointValues(field); @@ -187,7 +187,7 @@ public static byte[] getMinPackedValue(IndexReader reader, String field) throws * * @see PointValues#getMaxPackedValue() */ - public static byte[] getMaxPackedValue(IndexReader reader, String field) throws IOException { + public static byte[] getMaxPackedValue(IndexReader reader, String field) { byte[] maxValue = null; for (LeafReaderContext ctx : reader.leaves()) { PointValues values = ctx.reader().getPointValues(field); @@ -473,21 +473,21 @@ public final long estimateDocCount(IntersectVisitor visitor) { /** * Returns minimum value for each dimension, packed, or null if {@link #size} is 0 */ - public abstract byte[] getMinPackedValue() throws IOException; + public abstract byte[] getMinPackedValue(); /** * Returns maximum value for each dimension, packed, or null if {@link #size} is 0 */ - public abstract byte[] getMaxPackedValue() throws IOException; + public abstract byte[] getMaxPackedValue(); /** Returns how many dimensions are represented in the values */ - public abstract int getNumDimensions() throws IOException; + public abstract int getNumDimensions(); /** Returns how many dimensions are used for the index */ - public abstract int getNumIndexDimensions() throws IOException; + public abstract int getNumIndexDimensions(); /** Returns the number of bytes per dimension */ - public abstract int getBytesPerDimension() throws IOException; + public abstract int getBytesPerDimension(); /** Returns the total number of indexed points across all documents. */ public abstract long size(); diff --git a/lucene/core/src/java/org/apache/lucene/index/PointValuesWriter.java b/lucene/core/src/java/org/apache/lucene/index/PointValuesWriter.java index 7bfde5c16ca1..490c3840783a 100644 --- a/lucene/core/src/java/org/apache/lucene/index/PointValuesWriter.java +++ b/lucene/core/src/java/org/apache/lucene/index/PointValuesWriter.java @@ -286,32 +286,32 @@ public PointValues getValues(String fieldName) { } return new PointValues() { @Override - public PointTree getPointTree() throws IOException { + public PointTree getPointTree() { return values; } @Override - public byte[] getMinPackedValue() throws IOException { + public byte[] getMinPackedValue() { throw new UnsupportedOperationException(); } @Override - public byte[] getMaxPackedValue() throws IOException { + public byte[] getMaxPackedValue() { throw new UnsupportedOperationException(); } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { throw new UnsupportedOperationException(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { throw new UnsupportedOperationException(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { throw new UnsupportedOperationException(); } diff --git a/lucene/core/src/java/org/apache/lucene/index/SlowCompositeCodecReaderWrapper.java b/lucene/core/src/java/org/apache/lucene/index/SlowCompositeCodecReaderWrapper.java index a7d8bf2abd78..be5a8dbb7662 100644 --- a/lucene/core/src/java/org/apache/lucene/index/SlowCompositeCodecReaderWrapper.java +++ b/lucene/core/src/java/org/apache/lucene/index/SlowCompositeCodecReaderWrapper.java @@ -17,7 +17,6 @@ package org.apache.lucene.index; import java.io.IOException; -import java.io.UncheckedIOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -613,7 +612,7 @@ public PointValues getValues(String field) { return new PointValues() { @Override - public PointTree getPointTree() throws IOException { + public PointTree getPointTree() { return new PointTree() { @Override @@ -681,110 +680,98 @@ public boolean moveToChild() throws IOException { @Override public byte[] getMinPackedValue() { - try { - byte[] minPackedValue = null; - for (PointValuesSub sub : values) { - if (minPackedValue == null) { - minPackedValue = sub.sub.getMinPackedValue().clone(); - } else { - byte[] leafMinPackedValue = sub.sub.getMinPackedValue(); - int numIndexDimensions = sub.sub.getNumIndexDimensions(); - int numBytesPerDimension = sub.sub.getBytesPerDimension(); - ArrayUtil.ByteArrayComparator comparator = - ArrayUtil.getUnsignedComparator(numBytesPerDimension); - for (int i = 0; i < numIndexDimensions; ++i) { - if (comparator.compare( - leafMinPackedValue, - i * numBytesPerDimension, - minPackedValue, - i * numBytesPerDimension) - < 0) { - System.arraycopy( + byte[] minPackedValue = null; + for (PointValuesSub sub : values) { + if (minPackedValue == null) { + minPackedValue = sub.sub.getMinPackedValue().clone(); + } else { + byte[] leafMinPackedValue = sub.sub.getMinPackedValue(); + int numIndexDimensions = sub.sub.getNumIndexDimensions(); + int numBytesPerDimension = sub.sub.getBytesPerDimension(); + ArrayUtil.ByteArrayComparator comparator = + ArrayUtil.getUnsignedComparator(numBytesPerDimension); + for (int i = 0; i < numIndexDimensions; ++i) { + if (comparator.compare( leafMinPackedValue, i * numBytesPerDimension, minPackedValue, - i * numBytesPerDimension, - numBytesPerDimension); - } + i * numBytesPerDimension) + < 0) { + System.arraycopy( + leafMinPackedValue, + i * numBytesPerDimension, + minPackedValue, + i * numBytesPerDimension, + numBytesPerDimension); } } } - return minPackedValue; - } catch (IOException e) { - throw new UncheckedIOException(e); } + return minPackedValue; } @Override public byte[] getMaxPackedValue() { - try { - byte[] maxPackedValue = null; - for (PointValuesSub sub : values) { - if (maxPackedValue == null) { - maxPackedValue = sub.sub.getMaxPackedValue().clone(); - } else { - byte[] leafMinPackedValue = sub.sub.getMaxPackedValue(); - int numIndexDimensions = sub.sub.getNumIndexDimensions(); - int numBytesPerDimension = sub.sub.getBytesPerDimension(); - ArrayUtil.ByteArrayComparator comparator = - ArrayUtil.getUnsignedComparator(numBytesPerDimension); - for (int i = 0; i < numIndexDimensions; ++i) { - if (comparator.compare( - leafMinPackedValue, - i * numBytesPerDimension, - maxPackedValue, - i * numBytesPerDimension) - > 0) { - System.arraycopy( + byte[] maxPackedValue = null; + for (PointValuesSub sub : values) { + if (maxPackedValue == null) { + maxPackedValue = sub.sub.getMaxPackedValue().clone(); + } else { + byte[] leafMinPackedValue = sub.sub.getMaxPackedValue(); + int numIndexDimensions = sub.sub.getNumIndexDimensions(); + int numBytesPerDimension = sub.sub.getBytesPerDimension(); + ArrayUtil.ByteArrayComparator comparator = + ArrayUtil.getUnsignedComparator(numBytesPerDimension); + for (int i = 0; i < numIndexDimensions; ++i) { + if (comparator.compare( leafMinPackedValue, i * numBytesPerDimension, maxPackedValue, - i * numBytesPerDimension, - numBytesPerDimension); - } + i * numBytesPerDimension) + > 0) { + System.arraycopy( + leafMinPackedValue, + i * numBytesPerDimension, + maxPackedValue, + i * numBytesPerDimension, + numBytesPerDimension); } } } - return maxPackedValue; - } catch (IOException e) { - throw new UncheckedIOException(e); } + return maxPackedValue; } }; } @Override - public byte[] getMinPackedValue() throws IOException { + public byte[] getMinPackedValue() { return getPointTree().getMinPackedValue(); } @Override - public byte[] getMaxPackedValue() throws IOException { + public byte[] getMaxPackedValue() { return getPointTree().getMaxPackedValue(); } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { return values.get(0).sub.getNumDimensions(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { return values.get(0).sub.getNumIndexDimensions(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { return values.get(0).sub.getBytesPerDimension(); } @Override public long size() { - try { - return getPointTree().size(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + return getPointTree().size(); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/index/SortingCodecReader.java b/lucene/core/src/java/org/apache/lucene/index/SortingCodecReader.java index 4cc052cea9f8..2f3ff5213dca 100644 --- a/lucene/core/src/java/org/apache/lucene/index/SortingCodecReader.java +++ b/lucene/core/src/java/org/apache/lucene/index/SortingCodecReader.java @@ -84,27 +84,27 @@ public PointTree getPointTree() throws IOException { } @Override - public byte[] getMinPackedValue() throws IOException { + public byte[] getMinPackedValue() { return in.getMinPackedValue(); } @Override - public byte[] getMaxPackedValue() throws IOException { + public byte[] getMaxPackedValue() { return in.getMaxPackedValue(); } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { return in.getNumDimensions(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { return in.getNumIndexDimensions(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { return in.getBytesPerDimension(); } diff --git a/lucene/core/src/java/org/apache/lucene/util/bkd/BKDReader.java b/lucene/core/src/java/org/apache/lucene/util/bkd/BKDReader.java index 9c991e6b1b4a..62e422924b82 100644 --- a/lucene/core/src/java/org/apache/lucene/util/bkd/BKDReader.java +++ b/lucene/core/src/java/org/apache/lucene/util/bkd/BKDReader.java @@ -1009,17 +1009,17 @@ public byte[] getMaxPackedValue() { } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { return config.numDims(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { return config.numIndexDims(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { return config.bytesPerDim(); } diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterReader.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterReader.java index 8ffbf45651d5..e4e0919a221f 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterReader.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterReader.java @@ -1212,14 +1212,11 @@ public void testIndexReaderWriterWithLeafSorter() throws IOException { Comparator leafSorter = Comparator.comparingLong( r -> { - try { - PointValues points = r.getPointValues(FIELD_NAME); - if (points != null) { - byte[] sortValue = - ASC_SORT ? points.getMinPackedValue() : points.getMaxPackedValue(); - return LongPoint.decodeDimension(sortValue, 0); - } - } catch (IOException _) { + PointValues points = r.getPointValues(FIELD_NAME); + if (points != null) { + byte[] sortValue = + ASC_SORT ? points.getMinPackedValue() : points.getMaxPackedValue(); + return LongPoint.decodeDimension(sortValue, 0); } return MISSING_VALUE; }); diff --git a/lucene/core/src/test/org/apache/lucene/util/TestDocIdSetBuilder.java b/lucene/core/src/test/org/apache/lucene/util/TestDocIdSetBuilder.java index efc8642383c4..d5b5cdb28ce2 100644 --- a/lucene/core/src/test/org/apache/lucene/util/TestDocIdSetBuilder.java +++ b/lucene/core/src/test/org/apache/lucene/util/TestDocIdSetBuilder.java @@ -334,27 +334,27 @@ public PointTree getPointTree() { } @Override - public byte[] getMinPackedValue() throws IOException { + public byte[] getMinPackedValue() { throw new UnsupportedOperationException(); } @Override - public byte[] getMaxPackedValue() throws IOException { + public byte[] getMaxPackedValue() { throw new UnsupportedOperationException(); } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { throw new UnsupportedOperationException(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { throw new UnsupportedOperationException(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { throw new UnsupportedOperationException(); } diff --git a/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java b/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java index 44959bdd7a3b..f56e14de9d41 100644 --- a/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java +++ b/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java @@ -2131,27 +2131,27 @@ public void visitDocValues(IntersectVisitor visitor) throws IOException { } @Override - public byte[] getMinPackedValue() throws IOException { + public byte[] getMinPackedValue() { return info.minPackedValue; } @Override - public byte[] getMaxPackedValue() throws IOException { + public byte[] getMaxPackedValue() { return info.maxPackedValue; } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { return info.fieldInfo.getPointDimensionCount(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { return info.fieldInfo.getPointDimensionCount(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { return info.fieldInfo.getPointNumBytes(); } diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/codecs/cranky/CrankyPointsFormat.java b/lucene/test-framework/src/java/org/apache/lucene/tests/codecs/cranky/CrankyPointsFormat.java index 17a500601dd0..9edc4225e559 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/codecs/cranky/CrankyPointsFormat.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/codecs/cranky/CrankyPointsFormat.java @@ -187,42 +187,27 @@ public void visitDocValues(IntersectVisitor visitor) throws IOException { } @Override - public byte[] getMinPackedValue() throws IOException { - if (random.nextInt(100) == 0) { - throw new IOException("Fake IOException"); - } + public byte[] getMinPackedValue() { return delegate.getMinPackedValue(); } @Override - public byte[] getMaxPackedValue() throws IOException { - if (random.nextInt(100) == 0) { - throw new IOException("Fake IOException"); - } + public byte[] getMaxPackedValue() { return delegate.getMaxPackedValue(); } @Override - public int getNumDimensions() throws IOException { - if (random.nextInt(100) == 0) { - throw new IOException("Fake IOException"); - } + public int getNumDimensions() { return delegate.getNumDimensions(); } @Override - public int getNumIndexDimensions() throws IOException { - if (random.nextInt(100) == 0) { - throw new IOException("Fake IOException"); - } + public int getNumIndexDimensions() { return delegate.getNumIndexDimensions(); } @Override - public int getBytesPerDimension() throws IOException { - if (random.nextInt(100) == 0) { - throw new IOException("Fake IOException"); - } + public int getBytesPerDimension() { return delegate.getBytesPerDimension(); } diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/index/AssertingLeafReader.java b/lucene/test-framework/src/java/org/apache/lucene/tests/index/AssertingLeafReader.java index 37c6b7de5c0c..24e1c55fbadc 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/index/AssertingLeafReader.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/index/AssertingLeafReader.java @@ -1523,31 +1523,31 @@ public PointTree getPointTree() throws IOException { } @Override - public byte[] getMinPackedValue() throws IOException { + public byte[] getMinPackedValue() { assertThread("Points", creationThread); return Objects.requireNonNull(in.getMinPackedValue()); } @Override - public byte[] getMaxPackedValue() throws IOException { + public byte[] getMaxPackedValue() { assertThread("Points", creationThread); return Objects.requireNonNull(in.getMaxPackedValue()); } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { assertThread("Points", creationThread); return in.getNumDimensions(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { assertThread("Points", creationThread); return in.getNumIndexDimensions(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { assertThread("Points", creationThread); return in.getBytesPerDimension(); } diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/index/BasePointsFormatTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/tests/index/BasePointsFormatTestCase.java index 0c4d7e1d7755..7bf19a8a95c2 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/index/BasePointsFormatTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/index/BasePointsFormatTestCase.java @@ -1375,27 +1375,27 @@ public void visitDocValues(IntersectVisitor visitor) { } @Override - public byte[] getMinPackedValue() throws IOException { + public byte[] getMinPackedValue() { throw new UnsupportedOperationException(); } @Override - public byte[] getMaxPackedValue() throws IOException { + public byte[] getMaxPackedValue() { throw new UnsupportedOperationException(); } @Override - public int getNumDimensions() throws IOException { + public int getNumDimensions() { throw new UnsupportedOperationException(); } @Override - public int getNumIndexDimensions() throws IOException { + public int getNumIndexDimensions() { throw new UnsupportedOperationException(); } @Override - public int getBytesPerDimension() throws IOException { + public int getBytesPerDimension() { throw new UnsupportedOperationException(); } From 061a404f9a7c9e0e1f1cb7fdfa3f4acf88bb1fa7 Mon Sep 17 00:00:00 2001 From: Alan Woodward Date: Tue, 14 Jul 2026 09:24:51 +0100 Subject: [PATCH 2/2] changes --- lucene/CHANGES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 31f6557969f0..d0748b1b735a 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -310,6 +310,8 @@ API Changes * GITHUB#16363: Add API to use a custom `DictionarySuggester` instead of hardcoded `GeneratingSuggester` +* GITHUB#16387: Don't throw IOException from PointValues metadata methods. (Alan Woodward) + New Features ---------------------