fix: Pass Knapsnak ptr to avoid compact multiple times (#40400)

Related to #40388

The small segments may be put into bucket twice due to value parameter
of Knapsnap.packWith

Signed-off-by: Congqi Xia <congqi.xia@zilliz.com>
This commit is contained in:
congqixia 2025-03-06 15:42:03 +08:00 committed by GitHub
parent 80213c0f6f
commit 5c5273f95e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -33,14 +33,14 @@ type Knapsack[T Sizable] struct {
candidates []T candidates []T
} }
func newKnapsack[T Sizable](name string, candidates []T) Knapsack[T] { func newKnapsack[T Sizable](name string, candidates []T) *Knapsack[T] {
sort.Slice(candidates, func(i, j int) bool { sort.Slice(candidates, func(i, j int) bool {
if candidates[i].getSegmentSize() != candidates[j].getSegmentSize() { if candidates[i].getSegmentSize() != candidates[j].getSegmentSize() {
return candidates[i].getSegmentSize() > candidates[j].getSegmentSize() return candidates[i].getSegmentSize() > candidates[j].getSegmentSize()
} }
return candidates[i].GetID() < candidates[j].GetID() return candidates[i].GetID() < candidates[j].GetID()
}) })
return Knapsack[T]{ return &Knapsack[T]{
name: name, name: name,
candidates: candidates, candidates: candidates,
} }
@ -61,13 +61,7 @@ func (c *Knapsack[T]) tryPack(size, maxLeftSize, minSegs, maxSegs int64) (bitset
} }
nSelections := selection.Count() nSelections := selection.Count()
var minUSegs uint if left > maxLeftSize || int64(nSelections) < minSegs {
if minSegs < 0 {
minUSegs = 0
} else {
minUSegs = uint(minSegs)
}
if left > maxLeftSize || nSelections < uint(minUSegs) {
selection.ClearAll() selection.ClearAll()
left = size left = size
} }
@ -103,7 +97,7 @@ func (c *Knapsack[T]) pack(size, maxLeftSize, minSegs, maxSegs int64) ([]T, int6
return segs, left return segs, left
} }
func (c *Knapsack[T]) packWith(size, maxLeftSize, minSegs, maxSegs int64, other Knapsack[T]) ([]T, int64) { func (c *Knapsack[T]) packWith(size, maxLeftSize, minSegs, maxSegs int64, other *Knapsack[T]) ([]T, int64) {
selection, left := c.tryPack(size, math.MaxInt64, 0, maxSegs) selection, left := c.tryPack(size, math.MaxInt64, 0, maxSegs)
if selection.Count() == 0 { if selection.Count() == 0 {
return nil, size return nil, size
@ -114,7 +108,7 @@ func (c *Knapsack[T]) packWith(size, maxLeftSize, minSegs, maxSegs int64, other
if otherSelection.Count() == 0 { if otherSelection.Count() == 0 {
// If the original selection already satisfied the requirements, return immediately // If the original selection already satisfied the requirements, return immediately
if left < maxLeftSize && selection.Count() >= uint(minSegs) { if left < maxLeftSize && int64(selection.Count()) >= minSegs {
return c.commit(selection), left return c.commit(selection), left
} }
return nil, size return nil, size
@ -124,6 +118,6 @@ func (c *Knapsack[T]) packWith(size, maxLeftSize, minSegs, maxSegs int64, other
return append(segs, otherSegs...), left return append(segs, otherSegs...), left
} }
func newSegmentPacker(name string, candidates []*SegmentInfo) Knapsack[*SegmentInfo] { func newSegmentPacker(name string, candidates []*SegmentInfo) *Knapsack[*SegmentInfo] {
return newKnapsack[*SegmentInfo](name, candidates) return newKnapsack(name, candidates)
} }