-
Notifications
You must be signed in to change notification settings - Fork 791
fix: return deep copies in GetScheduledPods to prevent data races #2164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,7 +17,6 @@ limitations under the License. | |
| package device | ||
|
|
||
| import ( | ||
| "maps" | ||
| "sync" | ||
|
|
||
| corev1 "k8s.io/api/core/v1" | ||
|
|
@@ -212,16 +211,32 @@ func (cd ContainerDevices) DeepCopy() ContainerDevices { | |
| } | ||
|
|
||
| func (c ContainerDevice) DeepCopy() ContainerDevice { | ||
| dup := ContainerDevice{ | ||
| return ContainerDevice{ | ||
| Idx: c.Idx, | ||
| UUID: c.UUID, | ||
| Type: c.Type, | ||
| Usedmem: c.Usedmem, | ||
| Usedcores: c.Usedcores, | ||
| } | ||
| if c.CustomInfo != nil { | ||
| dup.CustomInfo = make(map[string]any, len(c.CustomInfo)) | ||
| maps.Copy(dup.CustomInfo, c.CustomInfo) | ||
| } | ||
|
|
||
| func (pd PodDevices) DeepCopyForMetrics() PodDevices { | ||
| if pd == nil { | ||
| return nil | ||
| } | ||
|
|
||
| dup := make(PodDevices, len(pd)) | ||
| for deviceType, podSingleDevice := range pd { | ||
| deviceCopy := make(PodSingleDevice, len(podSingleDevice)) | ||
| for containerIndex, containerDevices := range podSingleDevice { | ||
| deviceCopy[containerIndex] = make(ContainerDevices, len(containerDevices)) | ||
| copy(deviceCopy[containerIndex], containerDevices) | ||
|
|
||
| for i := range deviceCopy[containerIndex] { | ||
| deviceCopy[containerIndex][i].CustomInfo = nil | ||
| } | ||
| } | ||
| dup[deviceType] = deviceCopy | ||
| } | ||
| return dup | ||
| } | ||
|
|
@@ -230,14 +245,13 @@ func (m *PodManager) GetScheduledPods() (map[k8stypes.UID]*PodInfo, error) { | |
| m.mutex.RLock() | ||
| defer m.mutex.RUnlock() | ||
|
|
||
| podCount := len(m.pods) | ||
| klog.InfoS("Retrieved scheduled pods", | ||
| "podCount", podCount, | ||
| ) | ||
|
|
||
| // Return a shallow copy of the pods map to avoid race conditions. | ||
| // This prevents a "concurrent map iteration and map write" fatal error. | ||
| podsCopy := make(map[k8stypes.UID]*PodInfo, podCount) | ||
| maps.Copy(podsCopy, m.pods) | ||
| podsCopy := make(map[k8stypes.UID]*PodInfo, len(m.pods)) | ||
| for uid, pod := range m.pods { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the only caller is cmd/scheduler/metrics.go:318 and it reads Namespace, Name, NodeID and Devices only, so cloning the whole corev1.Pod spec and status per pod per scrape is a lot of garbage for nothing, did u consider copying just PodInfo w/ the pod ptr left alone?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Excellent point. I revised GetScheduledPods to construct a metrics-specific PodInfo snapshot: it retains the original Pod pointer for name/namespace identity checks while copying NodeID and cloning device allocations via DeepCopyForMetrics(). This avoids generating garbage by copying the full corev1.Pod spec and status on every Prometheus scrape cycle. |
||
| podsCopy[uid] = &PodInfo{ | ||
| Pod: pod.Pod, | ||
| NodeID: pod.NodeID, | ||
| Devices: pod.Devices.DeepCopyForMetrics(), | ||
| } | ||
| } | ||
| return podsCopy, nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Keep
CustomInfoomission limited to metrics snapshots.ContainerDevice.DeepCopy()is also used byPodInfo.DeepCopy()throughPodDevices.DeepCopy(), so Line 213 now silently discards metadata for every generic copy, not onlyGetScheduledPods().DeepCopyForMetrics()already provides the intended redaction.pkg/device/pods.go#L213-L220: restoreCustomInfopreservation/isolation in the generic copy path; retain its omission only inDeepCopyForMetrics().pkg/device/pod_test.go#L537-L545: assert generic copies preserveCustomInfo; keep the nil assertion in the metrics-snapshot test.📍 Affects 2 files
pkg/device/pods.go#L213-L220(this comment)pkg/device/pod_test.go#L537-L545🤖 Prompt for AI Agents