Skip to content

[Backport 10x] Move finishMerge to a finally block so it always runs (#14977) - #16481

Open
john-mlika wants to merge 3 commits into
apache:branch_10xfrom
john-mlika:10x-backport-14977-finishmerge
Open

[Backport 10x] Move finishMerge to a finally block so it always runs (#14977)#16481
john-mlika wants to merge 3 commits into
apache:branch_10xfrom
john-mlika:10x-backport-14977-finishmerge

Conversation

@john-mlika

@john-mlika john-mlika commented Aug 3, 2026

Copy link
Copy Markdown

Backport of #14977 to branch_10x.

#15732 removed the previous KnnVectorsReader#finishMerge() caller on this branch, while #14977
was never backported. Vector inputs can therefore retain SEQUENTIAL read advice after a merge.
Details and reproduction are in #16419.

This restores SegmentMerger#cleanupMerge() and its two IndexWriter call sites, restores the
strict AssertingKnnVectorsFormat invariant, and adds a regression test. The KnnVectorsWriter
hunk from #14977 is omitted because it is already present here.

@john-mlika john-mlika changed the title Backport #14977 to branch_10x: invoke KnnVectorsReader#finishMerge() from SegmentMerger#cleanupMerge() [Backport 10x] Move finishMerge to a finally block so it always runs (#14977) Aug 3, 2026

@msokolov msokolov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good; I just have a few small comments. Also there seems to be a merge conflict. Can you address these things? Then I'll merge this and put it on a list of bugfixes for a potential 10.5.1

}

merge.mergeStartNS = System.nanoTime();
merge.mergeStartNS = System.nanoTime();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is there something funky with the indentation here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

don't think so? the line just moved inside the try block

}
}

private static Codec hnswFloatCodec() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We have TestUtil.alwaysDocValuesFormat for this; I think you can use it instead?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

updated to use alwaysKnnVectorsFormat here which is the vector equivalent


private static final int DIM = 16;

public void testSequentialAdviceIsRevertedAfterMerge() throws Exception {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the nice test!


public void testSequentialAdviceIsRevertedAfterMerge() throws Exception {
Recorder recorder = new Recorder();
try (Directory raw = new ByteBuffersDirectory();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IDK, should we use new MMapDirectory(createTempDir()) instead, just to more closely mirror the actual use case -- maybe someday somebody disables IOContext hinting on in-memory directories??

for (int seg = 0; seg < 2; seg++) {
for (int i = 0; i < 64; i++) {
Document doc = new Document();
float[] v = new float[DIM];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's use BaseKnnVectorsFormatTestCase.randomNormalizedVector -- unless it's somehow not accessible here?

List<String> sawSequential = new ArrayList<>();
for (Map.Entry<String, List<String>> e : recorder.snapshot().entrySet()) {
String file = e.getKey();
if (file.endsWith(".vec") == false) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lucene99FlatVectorsFormat.VECTOR_DATA_EXTENSION


synchronized Map<String, List<String>> snapshot() {
Map<String, List<String>> copy = new LinkedHashMap<>();
for (Map.Entry<String, List<String>> e : events.entrySet()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure the snapshot method is really necessary since we don't expect any activity after the forceMerge? Could we return events directly? If we want to guard against any future modification, we could replace events with null, or an unmodifiable map.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

updated to return events directly and dropped the copy

@msokolov

msokolov commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

I used the github webui to resolve the CHANGES.txt conflict -- but IDK where it puts that; you probably need to do the same on your PR branch

- use MMapDirectory(createTempDir()) instead of ByteBuffersDirectory
- use TestUtil#alwaysKnnVectorsFormat instead of a hand-rolled FilterCodec
- use BaseKnnVectorsFormatTestCase#randomNormalizedVector for vector values
- reference Lucene99FlatVectorsFormat#VECTOR_DATA_EXTENSION instead of .vec
- drop the defensive copy in Recorder#snapshot, return the map directly
@john-mlika

Copy link
Copy Markdown
Author

addressed the comments and resolved the conflict. should be good for another look now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants