Skip to content

Commit 4b52cf4

Browse files
authored
Fix potential file leak in ES816BinaryQuantizedVectorsWriter (#120014)
We are creating tmp files that might not get closed if an exception happens just after it. This commit makes sure all errors are handle properly and files are getting closed and deleted.
1 parent b1f4fa7 commit 4b52cf4

File tree

3 files changed

+55
-35
lines changed

3 files changed

+55
-35
lines changed

docs/changelog/120014.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 120014
2+
summary: Fix potential file leak in ES816BinaryQuantizedVectorsWriter
3+
area: Search
4+
type: bug
5+
issues:
6+
- 119981

muted-tests.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,6 @@ tests:
242242
- class: org.elasticsearch.lucene.RollingUpgradeSearchableSnapshotIndexCompatibilityIT
243243
method: testMountSearchableSnapshot {p0=[9.0.0, 9.0.0, 8.18.0]}
244244
issue: https://github.com/elastic/elasticsearch/issues/119980
245-
- class: org.elasticsearch.index.codec.vectors.es816.ES816HnswBinaryQuantizedVectorsFormatTests
246-
method: testRandomExceptions
247-
issue: https://github.com/elastic/elasticsearch/issues/119981
248245
- class: org.elasticsearch.multi_cluster.MultiClusterYamlTestSuiteIT
249246
issue: https://github.com/elastic/elasticsearch/issues/119983
250247
- class: org.elasticsearch.lucene.RollingUpgradeSearchableSnapshotIndexCompatibilityIT

server/src/test/java/org/elasticsearch/index/codec/vectors/es816/ES816BinaryQuantizedVectorsWriter.java

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -437,46 +437,66 @@ private CloseableRandomVectorScorerSupplier mergeOneFieldToIndex(
437437
float[] centroid,
438438
float cDotC
439439
) throws IOException {
440-
long vectorDataOffset = binarizedVectorData.alignFilePointer(Float.BYTES);
441-
final IndexOutput tempQuantizedVectorData = segmentWriteState.directory.createTempOutput(
442-
binarizedVectorData.getName(),
443-
"temp",
444-
segmentWriteState.context
445-
);
446-
final IndexOutput tempScoreQuantizedVectorData = segmentWriteState.directory.createTempOutput(
447-
binarizedVectorData.getName(),
448-
"score_temp",
449-
segmentWriteState.context
450-
);
451-
IndexInput binarizedDataInput = null;
452-
IndexInput binarizedScoreDataInput = null;
453-
boolean success = false;
454-
int descritizedDimension = BQVectorUtils.discretize(fieldInfo.getVectorDimension(), 64);
455-
BinaryQuantizer quantizer = new BinaryQuantizer(
440+
final long vectorDataOffset = binarizedVectorData.alignFilePointer(Float.BYTES);
441+
final int descritizedDimension = BQVectorUtils.discretize(fieldInfo.getVectorDimension(), 64);
442+
final BinaryQuantizer quantizer = new BinaryQuantizer(
456443
fieldInfo.getVectorDimension(),
457444
descritizedDimension,
458445
fieldInfo.getVectorSimilarityFunction()
459446
);
447+
448+
IndexOutput tempQuantizedVectorData = null;
449+
IndexOutput tempScoreQuantizedVectorData = null;
450+
final DocsWithFieldSet docsWithField;
451+
boolean success = false;
452+
460453
try {
454+
tempQuantizedVectorData = segmentWriteState.directory.createTempOutput(
455+
binarizedVectorData.getName(),
456+
"temp",
457+
segmentWriteState.context
458+
);
459+
tempScoreQuantizedVectorData = segmentWriteState.directory.createTempOutput(
460+
binarizedVectorData.getName(),
461+
"score_temp",
462+
segmentWriteState.context
463+
);
461464
FloatVectorValues floatVectorValues = KnnVectorsWriter.MergedVectorValues.mergeFloatVectorValues(fieldInfo, mergeState);
462465
if (fieldInfo.getVectorSimilarityFunction() == COSINE) {
463466
floatVectorValues = new NormalizedFloatVectorValues(floatVectorValues);
464467
}
465-
DocsWithFieldSet docsWithField = writeBinarizedVectorAndQueryData(
468+
docsWithField = writeBinarizedVectorAndQueryData(
466469
tempQuantizedVectorData,
467470
tempScoreQuantizedVectorData,
468471
floatVectorValues,
469472
centroid,
470473
quantizer
471474
);
472475
CodecUtil.writeFooter(tempQuantizedVectorData);
473-
IOUtils.close(tempQuantizedVectorData);
476+
CodecUtil.writeFooter(tempScoreQuantizedVectorData);
477+
success = true;
478+
} finally {
479+
if (success) {
480+
IOUtils.close(tempQuantizedVectorData, tempScoreQuantizedVectorData);
481+
} else {
482+
IOUtils.closeWhileHandlingException(tempQuantizedVectorData, tempScoreQuantizedVectorData);
483+
if (tempQuantizedVectorData != null) {
484+
IOUtils.deleteFilesIgnoringExceptions(segmentWriteState.directory, tempQuantizedVectorData.getName());
485+
}
486+
if (tempScoreQuantizedVectorData != null) {
487+
IOUtils.deleteFilesIgnoringExceptions(segmentWriteState.directory, tempScoreQuantizedVectorData.getName());
488+
}
489+
}
490+
}
491+
492+
IndexInput binarizedDataInput = null;
493+
IndexInput binarizedScoreDataInput = null;
494+
success = false;
495+
try {
474496
binarizedDataInput = segmentWriteState.directory.openInput(tempQuantizedVectorData.getName(), segmentWriteState.context);
475497
binarizedVectorData.copyBytes(binarizedDataInput, binarizedDataInput.length() - CodecUtil.footerLength());
476-
long vectorDataLength = binarizedVectorData.getFilePointer() - vectorDataOffset;
498+
final long vectorDataLength = binarizedVectorData.getFilePointer() - vectorDataOffset;
477499
CodecUtil.retrieveChecksum(binarizedDataInput);
478-
CodecUtil.writeFooter(tempScoreQuantizedVectorData);
479-
IOUtils.close(tempScoreQuantizedVectorData);
480500
binarizedScoreDataInput = segmentWriteState.directory.openInput(
481501
tempScoreQuantizedVectorData.getName(),
482502
segmentWriteState.context
@@ -490,10 +510,9 @@ private CloseableRandomVectorScorerSupplier mergeOneFieldToIndex(
490510
cDotC,
491511
docsWithField
492512
);
493-
success = true;
494513
final IndexInput finalBinarizedDataInput = binarizedDataInput;
495514
final IndexInput finalBinarizedScoreDataInput = binarizedScoreDataInput;
496-
OffHeapBinarizedVectorValues vectorValues = new OffHeapBinarizedVectorValues.DenseOffHeapVectorValues(
515+
final OffHeapBinarizedVectorValues vectorValues = new OffHeapBinarizedVectorValues.DenseOffHeapVectorValues(
497516
fieldInfo.getVectorDimension(),
498517
docsWithField.cardinality(),
499518
centroid,
@@ -503,7 +522,7 @@ private CloseableRandomVectorScorerSupplier mergeOneFieldToIndex(
503522
vectorsScorer,
504523
finalBinarizedDataInput
505524
);
506-
RandomVectorScorerSupplier scorerSupplier = vectorsScorer.getRandomVectorScorerSupplier(
525+
final RandomVectorScorerSupplier scorerSupplier = vectorsScorer.getRandomVectorScorerSupplier(
507526
fieldInfo.getVectorSimilarityFunction(),
508527
new OffHeapBinarizedQueryVectorValues(
509528
finalBinarizedScoreDataInput,
@@ -513,22 +532,20 @@ private CloseableRandomVectorScorerSupplier mergeOneFieldToIndex(
513532
),
514533
vectorValues
515534
);
535+
final String tempQuantizedVectorDataName = tempQuantizedVectorData.getName();
536+
final String tempScoreQuantizedVectorDataName = tempScoreQuantizedVectorData.getName();
537+
success = true;
516538
return new BinarizedCloseableRandomVectorScorerSupplier(scorerSupplier, vectorValues, () -> {
517539
IOUtils.close(finalBinarizedDataInput, finalBinarizedScoreDataInput);
518540
IOUtils.deleteFilesIgnoringExceptions(
519541
segmentWriteState.directory,
520-
tempQuantizedVectorData.getName(),
521-
tempScoreQuantizedVectorData.getName()
542+
tempQuantizedVectorDataName,
543+
tempScoreQuantizedVectorDataName
522544
);
523545
});
524546
} finally {
525547
if (success == false) {
526-
IOUtils.closeWhileHandlingException(
527-
tempQuantizedVectorData,
528-
tempScoreQuantizedVectorData,
529-
binarizedDataInput,
530-
binarizedScoreDataInput
531-
);
548+
IOUtils.closeWhileHandlingException(binarizedDataInput, binarizedScoreDataInput);
532549
IOUtils.deleteFilesIgnoringExceptions(
533550
segmentWriteState.directory,
534551
tempQuantizedVectorData.getName(),

0 commit comments

Comments
 (0)