Skip to content

Commit 462b753

Browse files
committed
let image cache do sort on write instead of on read to avoid data
race and improve efficienty
1 parent 7c7ce47 commit 462b753

File tree

3 files changed

+14
-17
lines changed

3 files changed

+14
-17
lines changed

pkg/kubelet/images/image_gc_manager.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,21 +113,26 @@ type imageCache struct {
113113
images []container.Image
114114
}
115115

116-
// set updates image cache.
116+
// set sorts the input list and updates image cache.
117+
// 'i' takes ownership of the list, you should not reference the list again
118+
// after calling this function.
117119
func (i *imageCache) set(images []container.Image) {
118120
i.Lock()
119121
defer i.Unlock()
122+
// The image list needs to be sorted when it gets read and used in
123+
// setNodeStatusImages. We sort the list on write instead of on read,
124+
// because the image cache is more often read than written
125+
sort.Sort(sliceutils.ByImageSize(images))
120126
i.images = images
121127
}
122128

123-
// get gets a sorted (by image size) image list from image cache.
124-
// There is a potentical data race in this function. See PR #60448
125-
// Because there is deepcopy function available currently, move sort
126-
// function inside this function
129+
// get gets image list from image cache.
130+
// NOTE: The caller of get() should not do mutating operations on the
131+
// returned list that could cause data race against other readers (e.g.
132+
// in-place sorting the returned list)
127133
func (i *imageCache) get() []container.Image {
128134
i.Lock()
129135
defer i.Unlock()
130-
sort.Sort(sliceutils.ByImageSize(i.images))
131136
return i.images
132137
}
133138

pkg/kubelet/images/image_gc_manager_test.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -548,16 +548,6 @@ func TestValidateImageGCPolicy(t *testing.T) {
548548
}
549549
}
550550

551-
func TestImageCacheReturnCopiedList(t *testing.T) {
552-
cache := &imageCache{}
553-
testList := []container.Image{{ID: "1"}, {ID: "2"}}
554-
cache.set(testList)
555-
list := cache.get()
556-
assert.Len(t, list, 2)
557-
list[0].ID = "3"
558-
assert.Equal(t, cache.get(), testList)
559-
}
560-
561551
func uint64Ptr(i uint64) *uint64 {
562552
return &i
563553
}

pkg/kubelet/nodestatus/setters.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,9 @@ func Images(nodeStatusMaxImages int32,
446446
}
447447

448448
for _, image := range containerImages {
449-
names := append(image.RepoDigests, image.RepoTags...)
449+
// make a copy to avoid modifying slice members of the image items in the list
450+
names := append([]string{}, image.RepoDigests...)
451+
names = append(names, image.RepoTags...)
450452
// Report up to MaxNamesPerImageInNodeStatus names per image.
451453
if len(names) > MaxNamesPerImageInNodeStatus {
452454
names = names[0:MaxNamesPerImageInNodeStatus]

0 commit comments

Comments
 (0)