Fix duplicate elements left by CollectionUtils.sortAndDedup#22445
Fix duplicate elements left by CollectionUtils.sortAndDedup#22445winklemad wants to merge 1 commit into
Conversation
PR Reviewer Guide 🔍(Review updated until commit b803375)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to b803375
Previous suggestionsSuggestions up to commit ca88f64
|
|
❌ Gradle check result for ca88f64: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
sortAndDedup tracked its last-retained value from the write cursor (deduped.next()) instead of the value it had just kept, so once the input held two or more consecutive runs of equal values every run after the first survived -- e.g. sortAndDedup([0, 0, 1, 1]) returned [0, 1, 1]. Track the retained value directly. BinaryFieldMapper dedups a document's multi-valued binary doc-values through this method, so affected documents stored duplicated, oversized values. Signed-off-by: winklemad <winklemad@outlook.com>
ca88f64 to
b803375
Compare
|
On the automated suggestion to replace To make that explicit I added a regression case with distinct |
|
Persistent review updated to latest commit b803375 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #22445 +/- ##
============================================
- Coverage 73.46% 73.46% -0.01%
+ Complexity 76477 76459 -18
============================================
Files 6104 6104
Lines 346568 346570 +2
Branches 49883 49884 +1
============================================
- Hits 254598 254594 -4
- Misses 71693 71727 +34
+ Partials 20277 20249 -28 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Description
CollectionUtils.sortAndDedup(List, Comparator)can leave duplicate elements in the list. After it retains a new unique value it updates its "last retained value" tracker from the wrong source, so once the input contains two or more consecutive runs of equal values, every run after the first survives.When a new unique
oldis found,cmpis assigneddeduped.next()— the value currently under the write cursor — instead ofold, the value actually being kept.cmpthen goes stale and the next comparison is made against the wrong value.Example:
sortAndDedup([0, 0, 1, 1], naturalOrder())returns[0, 1, 1](expected[0, 1])sortAndDedup([2, 2, 2, 3, 3], naturalOrder())returns[2, 3, 3](expected[2, 3])It triggers whenever a sorted run of ≥2 equal values is followed by another run of ≥2 equal values.
Impact
BinaryFieldMappercalls this to dedup a document's multi-valuedbinarydoc-values before serialization:A document whose binary field holds values like
{aa, aa, bb, bb}is stored as[aa, bb, bb]— duplicated, oversized stored doc-values.Root cause / fix
The sibling
BytesRefUtils.sortAndDedupuses the standard adjacentprevious/currentcompare and is correct. Track the retained value directly instead of the write-cursor value:This keeps the original in-place write and the reference-equality skip (avoids a redundant
setwhen the value is already in position); it only corrects which valuecmptracks. This is the onlyListIterator-based dedup in the class, andBinaryFieldMapperis its only production caller.Test
Extended
CollectionUtilsTests.testSortAndDedupwith multiple-consecutive-run cases ([0,0,1,1],[2,2,2,3,3],[0,0,1,1,2,2], runs followed by a trailing unique, unsorted multi-group input, and a reverse comparator). The existingassertDedupedhelper already exercises bothArrayListandLinkedListand asserts that adjacent elements differ. The new cases fail before the fix (spurious duplicates survive) and pass after.:libs:opensearch-coreprecommit and theCollectionUtilsTestssuite are green locally.Related Issues
No linked issue — found by reading the code.
Check List
--signoff.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.