53 lines
1.8 KiB
Diff
53 lines
1.8 KiB
Diff
# UNDF: UNDF-2026-000000768
|
||
# UNDF: (leave blank)
|
||
# minio-0001: healingTracker.isHealed() uses slices.Contains(HealedBuckets, bucket) → O(B×H)
|
||
#
|
||
# File: cmd/background-newdisks-heal-ops.go
|
||
# Function: healingTracker.isHealed()
|
||
# Called from: cmd/global-heal.go line 270, inside `for _, bucket := range healBuckets`
|
||
#
|
||
# The heal loop iterates all buckets (B) and for each calls isHealed() which
|
||
# does slices.Contains over HealedBuckets (H). As healing progresses, H grows
|
||
# toward B, making total cost O(B²). With 10K+ buckets this is significant.
|
||
#
|
||
# Irony: setQueuedBuckets() already builds a set.CreateStringSet(HealedBuckets...)
|
||
# for the same data, but isHealed() doesn't use it.
|
||
#
|
||
# Fix: maintain a map[string]struct{} alongside the slice for O(1) lookup.
|
||
# Severity: MEDIUM (O(B²) during disk healing, B = number of buckets)
|
||
# Overhead ratio: ~250x at B=500
|
||
#
|
||
--- a/cmd/background-newdisks-heal-ops.go
|
||
+++ b/cmd/background-newdisks-heal-ops.go
|
||
@@ -48,6 +48,7 @@
|
||
type healingTracker struct {
|
||
mu *sync.RWMutex `msg:"-"`
|
||
+ healedSet map[string]struct{} `msg:"-"` // O(1) lookup mirror of HealedBuckets
|
||
|
||
ID string
|
||
PoolIndex int
|
||
@@ -163,6 +164,7 @@
|
||
func (h *healingTracker) resetHealStatusCounters() {
|
||
h.HealedBuckets = nil
|
||
+ h.healedSet = make(map[string]struct{})
|
||
h.QueuedBuckets = nil
|
||
h.ItemsHealed = 0
|
||
h.ItemsFailed = 0
|
||
@@ -269,7 +271,8 @@
|
||
func (h *healingTracker) isHealed(bucket string) bool {
|
||
h.mu.RLock()
|
||
defer h.mu.RUnlock()
|
||
- return slices.Contains(h.HealedBuckets, bucket)
|
||
+ _, ok := h.healedSet[bucket]
|
||
+ return ok
|
||
}
|
||
|
||
@@ -298,6 +301,9 @@
|
||
h.ResumeBytesSkipped = h.BytesSkipped
|
||
h.HealedBuckets = append(h.HealedBuckets, bucket)
|
||
+ if h.healedSet == nil {
|
||
+ h.healedSet = make(map[string]struct{})
|
||
+ }
|
||
+ h.healedSet[bucket] = struct{}{}
|
||
for i, b := range h.QueuedBuckets {
|
||
if b == bucket {
|