Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lucene/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ Other
* GITHUB#14761: Use more Comparators for PriorityQueue implementations. (Simon Cooper)
* GITHUB#14817: Refactor some complex uses of PriorityQueue to use Comparators. (Simon Cooper)

* GITHUB#14607: Revise strategy for opening an index for reading (Rahul Goswami)
======================= Lucene 10.4.0 =======================

API Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ public void testFailOpenOldIndex() throws IOException {
assertTrue(
ex.getMessage()
.contains(
"This Lucene version only supports indexes created with major version "
"This Lucene version only supports indexes with major version "
+ Version.LATEST.major
+ " or later"));
// now open with allowed min version
Expand Down
139 changes: 87 additions & 52 deletions lucene/core/src/java/org/apache/lucene/index/SegmentInfos.java
Original file line number Diff line number Diff line change
Expand Up @@ -346,30 +346,12 @@ public static final SegmentInfos readCommit(
input);
}

if (indexCreatedVersion < minSupportedMajorVersion) {
throw new IndexFormatTooOldException(
input,
"Index created with Lucene "
+ indexCreatedVersion
+ ".x is not supported by Lucene "
+ Version.LATEST
+ ". This Lucene version only supports indexes created with major version "
+ minSupportedMajorVersion
+ " or later (found: "
+ indexCreatedVersion
+ ", minimum: "
+ minSupportedMajorVersion
+ "). To resolve this issue: (1) Re-index your data using Lucene "
+ Version.LATEST.major
+ ".x, or (2) Use an older Lucene version that supports your index format.");
}

SegmentInfos infos = new SegmentInfos(indexCreatedVersion);
infos.id = id;
infos.generation = generation;
infos.lastGeneration = generation;
infos.luceneVersion = luceneVersion;
parseSegmentInfos(directory, input, infos, format);
parseSegmentInfos(directory, input, infos, format, minSupportedMajorVersion);
return infos;

} catch (Throwable t) {
Expand All @@ -385,7 +367,12 @@ public static final SegmentInfos readCommit(
}

private static void parseSegmentInfos(
Directory directory, DataInput input, SegmentInfos infos, int format) throws IOException {
Directory directory,
DataInput input,
SegmentInfos infos,
int format,
int minSupportedMajorVersion)
throws IOException {
infos.version = CodecUtil.readBELong(input);
// System.out.println("READ sis version=" + infos.version);
infos.counter = input.readVLong();
Expand All @@ -402,6 +389,7 @@ private static void parseSegmentInfos(
}

long totalDocs = 0;

for (int seg = 0; seg < numSegments; seg++) {
String segName = input.readString();
byte[] segmentID = new byte[StringHelper.ID_LENGTH];
Expand All @@ -410,6 +398,85 @@ private static void parseSegmentInfos(
SegmentInfo info =
codec.segmentInfoFormat().read(directory, segName, segmentID, IOContext.READONCE);
info.setCodec(codec);
Version segMinVersion = info.getMinVersion();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it a functional change to move this version checking early in the function? It makes reviewing harder since the diffs look bigger and one has to carefully read and scroll around to compare by eyeball, so if it's not needed, let's leave it where it was.

Copy link
Contributor Author

@rahulgoswami rahulgoswami Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that was exactly the intention- to move the check early in the function to fail fast. Agree it makes the reviewing trickier. Will incorporate the suggestion.

Version segmentVersion = info.getVersion();

if (!segmentVersion.onOrAfter(infos.minSegmentLuceneVersion)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we prefer == false to ! for clarity - it helps to avoid mistakes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I generally find the ! to be more readable in a natural language flow. Will follow Lucene's convention with == false.

throw new CorruptIndexException(
"segments file recorded minSegmentLuceneVersion="
+ infos.minSegmentLuceneVersion
+ " but segment="
+ info
+ " has older version="
+ segmentVersion,
input);
}

if (infos.indexCreatedVersionMajor >= 7
&& segmentVersion.major < infos.indexCreatedVersionMajor) {
throw new CorruptIndexException(
"segments file recorded indexCreatedVersionMajor="
+ infos.indexCreatedVersionMajor
+ " but segment="
+ info
+ " has older version="
+ segmentVersion,
input);
}

if (infos.indexCreatedVersionMajor >= 7 && segMinVersion == null) {
throw new CorruptIndexException(
"segments infos must record minVersion with indexCreatedVersionMajor="
+ infos.indexCreatedVersionMajor,
input);
}

// if trying to open some random old index (< Lucene 7)
if (segMinVersion == null) {
if (infos.indexCreatedVersionMajor < minSupportedMajorVersion) {
throw new IndexFormatTooOldException(
input,
"Index created with Lucene "
+ infos.indexCreatedVersionMajor
+ ".x is not supported by Lucene "
+ Version.LATEST
+ ". This Lucene version only supports indexes created with major version "
+ minSupportedMajorVersion
+ " or later (found: "
+ infos.indexCreatedVersionMajor
+ ", minimum: "
+ minSupportedMajorVersion
+ "). To resolve this issue: (1) Re-index your data using Lucene "
+ Version.LATEST.major
+ ".x, or (2) Use an older Lucene version that supports your index format.");
} else {
throw new CorruptIndexException(
"segments infos must record minVersion with indexCreatedVersionMajor="
+ infos.indexCreatedVersionMajor,
input);
}
}

if (segMinVersion.major < minSupportedMajorVersion) {
throw new IndexFormatTooOldException(
input,
"Index has segment traces from Lucene version "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what you mean by "traces" here? Maybe like "traces of an older version"? I think it will be clearer to just say "Index segment derived from version "?

+ segMinVersion.major
+ ".x and is not supported by Lucene "
+ Version.LATEST
+ ". This Lucene version only supports indexes with major version "
+ minSupportedMajorVersion
+ " or later (found: "
+ segMinVersion.major
+ ", minimum supported: "
+ minSupportedMajorVersion
+ "). To resolve this issue: (1) Re-index your data using Lucene "
+ minSupportedMajorVersion
+ ".x or later (preferably "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's strike "preferably" and say explicitly what is allowed

+ Version.LATEST.major
+ ".x), or (2) Use an older Lucene version that supports your index format.");
}

totalDocs += info.maxDoc();
long delGen = CodecUtil.readBELong(input);
int delCount = CodecUtil.readBEInt(input);
Expand Down Expand Up @@ -463,38 +530,6 @@ private static void parseSegmentInfos(
}
siPerCommit.setDocValuesUpdatesFiles(dvUpdateFiles);
infos.add(siPerCommit);

Version segmentVersion = info.getVersion();

if (segmentVersion.onOrAfter(infos.minSegmentLuceneVersion) == false) {
throw new CorruptIndexException(
"segments file recorded minSegmentLuceneVersion="
+ infos.minSegmentLuceneVersion
+ " but segment="
+ info
+ " has older version="
+ segmentVersion,
input);
}

if (infos.indexCreatedVersionMajor >= 7
&& segmentVersion.major < infos.indexCreatedVersionMajor) {
throw new CorruptIndexException(
"segments file recorded indexCreatedVersionMajor="
+ infos.indexCreatedVersionMajor
+ " but segment="
+ info
+ " has older version="
+ segmentVersion,
input);
}

if (infos.indexCreatedVersionMajor >= 7 && info.getMinVersion() == null) {
throw new CorruptIndexException(
"segments infos must record minVersion with indexCreatedVersionMajor="
+ infos.indexCreatedVersionMajor,
input);
}
}

infos.userData = input.readMapOfStrings();
Expand Down
Loading