Skip to content

Commit 085a0ae

Browse files
authored
Move finishMerge to a finally block so it always runs (#14977)
There are some cases where KnnVectorsReader.finishMerge is not always run, if an exception is thrown. This can lead to ReadAdvice not being reset properly. This puts finishMerge in a finally block, so it is always run regardless of merge outcome.
1 parent 71ea58a commit 085a0ae

File tree

6 files changed

+55
-46
lines changed

6 files changed

+55
-46
lines changed

lucene/core/src/java/org/apache/lucene/codecs/KnnVectorsWriter.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,9 @@ public final void merge(MergeState mergeState) throws IOException {
109109
}
110110
}
111111
}
112-
finishMerge(mergeState);
113112
finish();
114113
}
115114

116-
private void finishMerge(MergeState mergeState) throws IOException {
117-
for (KnnVectorsReader reader : mergeState.knnVectorsReaders) {
118-
if (reader != null) {
119-
reader.finishMerge();
120-
}
121-
}
122-
}
123-
124115
/** Tracks state of one sub-reader that we are merging */
125116
private static class FloatVectorValuesSub extends DocIDMerger.Sub {
126117

lucene/core/src/java/org/apache/lucene/index/IndexWriter.java

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,23 +3447,26 @@ public void addIndexesReaderMerge(MergePolicy.OneMerge merge) throws IOException
34473447
globalFieldNumberMap,
34483448
context,
34493449
intraMergeExecutor);
3450-
3451-
if (!merger.shouldMerge()) {
3452-
return;
3453-
}
3454-
3455-
merge.checkAborted();
3456-
synchronized (this) {
3457-
runningAddIndexesMerges.add(merger);
3458-
}
3459-
merge.mergeStartNS = System.nanoTime();
34603450
try {
3461-
merger.merge(); // merge 'em
3462-
} finally {
3451+
if (!merger.shouldMerge()) {
3452+
return;
3453+
}
3454+
3455+
merge.checkAborted();
34633456
synchronized (this) {
3464-
runningAddIndexesMerges.remove(merger);
3465-
notifyAll();
3457+
runningAddIndexesMerges.add(merger);
3458+
}
3459+
merge.mergeStartNS = System.nanoTime();
3460+
try {
3461+
merger.merge(); // merge 'em
3462+
} finally {
3463+
synchronized (this) {
3464+
runningAddIndexesMerges.remove(merger);
3465+
notifyAll();
3466+
}
34663467
}
3468+
} finally {
3469+
merger.cleanupMerge();
34673470
}
34683471

34693472
merge.setMergeInfo(
@@ -5238,32 +5241,36 @@ public int length() {
52385241
globalFieldNumberMap,
52395242
context,
52405243
intraMergeExecutor);
5241-
merge.info.setSoftDelCount(Math.toIntExact(softDeleteCount.get()));
5242-
merge.checkAborted();
5243-
52445244
MergeState mergeState = merger.mergeState;
52455245
MergeState.DocMap[] docMaps;
5246-
if (reorderDocMaps == null) {
5247-
docMaps = mergeState.docMaps;
5248-
} else {
5249-
// Since the reader was reordered, we passed a merged view to MergeState and from its
5250-
// perspective there is a single input segment to the merge and the
5251-
// SlowCompositeCodecReaderWrapper is effectively doing the merge.
5252-
assert mergeState.docMaps.length == 1
5253-
: "Got " + mergeState.docMaps.length + " docMaps, but expected 1";
5254-
MergeState.DocMap compactionDocMap = mergeState.docMaps[0];
5255-
docMaps = new MergeState.DocMap[reorderDocMaps.length];
5256-
for (int i = 0; i < docMaps.length; ++i) {
5257-
MergeState.DocMap reorderDocMap = reorderDocMaps[i];
5258-
docMaps[i] = docID -> compactionDocMap.get(reorderDocMap.get(docID));
5246+
try {
5247+
merge.info.setSoftDelCount(Math.toIntExact(softDeleteCount.get()));
5248+
merge.checkAborted();
5249+
5250+
if (reorderDocMaps == null) {
5251+
docMaps = mergeState.docMaps;
5252+
} else {
5253+
// Since the reader was reordered, we passed a merged view to MergeState and from its
5254+
// perspective there is a single input segment to the merge and the
5255+
// SlowCompositeCodecReaderWrapper is effectively doing the merge.
5256+
assert mergeState.docMaps.length == 1
5257+
: "Got " + mergeState.docMaps.length + " docMaps, but expected 1";
5258+
MergeState.DocMap compactionDocMap = mergeState.docMaps[0];
5259+
docMaps = new MergeState.DocMap[reorderDocMaps.length];
5260+
for (int i = 0; i < docMaps.length; ++i) {
5261+
MergeState.DocMap reorderDocMap = reorderDocMaps[i];
5262+
docMaps[i] = docID -> compactionDocMap.get(reorderDocMap.get(docID));
5263+
}
52595264
}
5260-
}
52615265

5262-
merge.mergeStartNS = System.nanoTime();
5266+
merge.mergeStartNS = System.nanoTime();
52635267

5264-
// This is where all the work happens:
5265-
if (merger.shouldMerge()) {
5266-
merger.merge();
5268+
// This is where all the work happens:
5269+
if (merger.shouldMerge()) {
5270+
merger.merge();
5271+
}
5272+
} finally {
5273+
merger.cleanupMerge();
52675274
}
52685275

52695276
assert mergeState.segmentInfo == merge.info.info;

lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.lucene.codecs.Codec;
2424
import org.apache.lucene.codecs.DocValuesConsumer;
2525
import org.apache.lucene.codecs.FieldsConsumer;
26+
import org.apache.lucene.codecs.KnnVectorsReader;
2627
import org.apache.lucene.codecs.KnnVectorsWriter;
2728
import org.apache.lucene.codecs.NormsConsumer;
2829
import org.apache.lucene.codecs.NormsProducer;
@@ -225,7 +226,7 @@ private void mergeTerms(SegmentWriteState segmentWriteState, SegmentReadState se
225226
}
226227
}
227228

228-
public void mergeFieldInfos() {
229+
private void mergeFieldInfos() {
229230
for (FieldInfos readerFieldInfos : mergeState.fieldInfos) {
230231
for (FieldInfo fi : readerFieldInfos) {
231232
fieldInfosBuilder.add(fi);
@@ -324,4 +325,12 @@ private void mergeWithLogging(
324325
+ " docs]");
325326
}
326327
}
328+
329+
void cleanupMerge() throws IOException {
330+
for (KnnVectorsReader reader : mergeState.knnVectorsReaders) {
331+
if (reader != null) {
332+
reader.finishMerge();
333+
}
334+
}
335+
}
327336
}

lucene/core/src/test/org/apache/lucene/index/TestDoc.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ private SegmentCommitInfo merge(
242242
new SameThreadExecutorService());
243243

244244
merger.merge();
245+
merger.cleanupMerge();
245246
r1.close();
246247
r2.close();
247248
si.setFiles(new HashSet<>(trackingDir.getCreatedFiles()));

lucene/core/src/test/org/apache/lucene/index/TestSegmentMerger.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ public void testMerge() throws IOException {
109109
newIOContext(random(), IOContext.merge(new MergeInfo(-1, -1, false, -1))),
110110
new SameThreadExecutorService());
111111
MergeState mergeState = merger.merge();
112+
merger.cleanupMerge();
112113
int docsMerged = mergeState.segmentInfo.maxDoc();
113114
assertTrue(docsMerged == 2);
114115
// Should be able to open a new SegmentReader against the new directory

lucene/test-framework/src/java/org/apache/lucene/tests/codecs/asserting/AssertingKnnVectorsFormat.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public Map<String, Long> getOffHeapByteSize(FieldInfo fieldInfo) {
238238
public void close() throws IOException {
239239
delegate.close();
240240
delegate.close(); // impls should be able to handle multiple closes
241-
assert finishMergeCount.get() <= 0 || mergeInstanceCount.get() == finishMergeCount.get();
241+
assert mergeInstanceCount.get() == finishMergeCount.get();
242242
}
243243

244244
@Override

0 commit comments

Comments
 (0)