Merge pull request #131581 from gauravkghildiyal/dra-avoid-unnecessary-slice-deletion

Introduce special handling for updates involving a single resource slice.
This commit is contained in:
Kubernetes Prow Robot
2025-05-02 03:23:55 -07:00
committed by GitHub
2 changed files with 75 additions and 26 deletions

View File

@@ -491,14 +491,17 @@ func (c *Controller) syncPool(ctx context.Context, poolName string) error {
if pool, ok := resources.Pools[poolName]; ok {
// Match each existing slice against the desired slices.
// Two slices match if they contain exactly the same
// device IDs, in an arbitrary order. Such a matched
// slice gets updated with the desired content if
// there is a difference.
// Two slices "match" if they contain exactly the
// same device IDs, in an arbitrary order. As a
// special case, slices are also considered
// "matched" in the scenario where there's a single
// existing slice and a single desired slice. Such a
// matched slice gets updated with the desired
// content if there is a difference.
//
// This supports updating the definition of devices
// in a slice. Adding or removing devices is done
// by deleting the old slice and creating a new one.
// In the case where there is more than one existing
// or desired slices, adding or removing devices is
// done by deleting the old slice and creating a new one.
//
// This is primarily a simplification of the code:
// to support adding or removing devices from
@@ -511,24 +514,32 @@ func (c *Controller) syncPool(ctx context.Context, poolName string) error {
// At the end of the loop, each current slice is either
// a match or obsolete.
currentSliceForDesiredSlice := make(map[int]*resourceapi.ResourceSlice, len(pool.Slices))
for _, currentSlice := range currentSlices {
matched := false
for i := range pool.Slices {
if _, ok := currentSliceForDesiredSlice[i]; ok {
// Already has a match.
continue
if len(currentSlices) == 1 && len(pool.Slices) == 1 {
// If there's just one existing slice and one desired slice, assume
// they "matched" such that if required, it is the existing slice
// which gets updated and we avoid an unnecessary deletion and
// recreation of the slice.
currentSliceForDesiredSlice[0] = currentSlices[0]
} else {
for _, currentSlice := range currentSlices {
matched := false
for i := range pool.Slices {
if _, ok := currentSliceForDesiredSlice[i]; ok {
// Already has a match.
continue
}
if sameSlice(currentSlice, &pool.Slices[i]) {
currentSliceForDesiredSlice[i] = currentSlice
logger.V(5).Info("Matched existing slice", "slice", klog.KObj(currentSlice), "matchIndex", i)
matched = true
break
}
}
if sameSlice(currentSlice, &pool.Slices[i]) {
currentSliceForDesiredSlice[i] = currentSlice
logger.V(5).Info("Matched existing slice", "slice", klog.KObj(currentSlice), "matchIndex", i)
matched = true
break
if !matched {
obsoleteSlices = append(obsoleteSlices, currentSlice)
logger.V(5).Info("Unmatched existing slice", "slice", klog.KObj(currentSlice))
}
}
if !matched {
obsoleteSlices = append(obsoleteSlices, currentSlice)
logger.V(5).Info("Unmatched existing slice", "slice", klog.KObj(currentSlice))
}
}
// Desired metadata which must be set in each slice.

View File

@@ -272,7 +272,7 @@ func TestControllerSyncPool(t *testing.T) {
},
expectedResourceSlices: nil,
},
"delete-and-add-slice": {
"one-existing-and-one-desired-slice-should-be-updated-inplace": {
nodeUID: nodeUID,
initialObjects: []runtime.Object{
// no devices
@@ -288,14 +288,52 @@ func TestControllerSyncPool(t *testing.T) {
},
},
expectedStats: Stats{
NumDeletes: 1,
NumUpdates: 1,
},
expectedResourceSlices: []resourceapi.ResourceSlice{
*MakeResourceSlice().Name(resourceSlice1).UID(resourceSlice1).ResourceVersion("1").
NodeOwnerReferences(ownerName, string(nodeUID)).NodeName(ownerName).
Driver(driverName).Devices([]resourceapi.Device{{Name: deviceName}}).
Pool(resourceapi.ResourcePool{Name: poolName, Generation: 1, ResourceSliceCount: 1}).Obj(),
},
},
"delete-and-add-slice-when-more-than-one-existing-or-desired-slice": {
nodeUID: nodeUID,
initialObjects: []runtime.Object{
// No devices in first ResourceSlice.
MakeResourceSlice().Name(resourceSlice1).UID(resourceSlice1).
NodeOwnerReferences(ownerName, string(nodeUID)).NodeName(ownerName).
Driver(driverName).Devices([]resourceapi.Device{}).
Pool(resourceapi.ResourcePool{Name: poolName, Generation: 1, ResourceSliceCount: 2}).Obj(),
MakeResourceSlice().Name(resourceSlice2).UID(resourceSlice2).
NodeOwnerReferences(ownerName, string(nodeUID)).NodeName(ownerName).
Driver(driverName).Devices([]resourceapi.Device{{Name: deviceName2}}).
Pool(resourceapi.ResourcePool{Name: poolName, Generation: 1, ResourceSliceCount: 2}).Obj(),
},
inputDriverResources: &DriverResources{
Pools: map[string]Pool{
poolName: {
Slices: []Slice{
{Devices: []resourceapi.Device{{Name: deviceName1}}},
{Devices: []resourceapi.Device{{Name: deviceName2}}},
},
},
},
},
expectedStats: Stats{
NumCreates: 1,
NumUpdates: 1,
NumDeletes: 1,
},
expectedResourceSlices: []resourceapi.ResourceSlice{
*MakeResourceSlice().Name(generatedName1).GenerateName(generateName).
NodeOwnerReferences(ownerName, string(nodeUID)).NodeName(ownerName).
Driver(driverName).Devices([]resourceapi.Device{{Name: deviceName}}).
Pool(resourceapi.ResourcePool{Name: poolName, Generation: 2, ResourceSliceCount: 1}).Obj(),
Driver(driverName).Devices([]resourceapi.Device{{Name: deviceName1}}).
Pool(resourceapi.ResourcePool{Name: poolName, Generation: 2, ResourceSliceCount: 2}).Obj(),
*MakeResourceSlice().Name(resourceSlice2).UID(resourceSlice2).ResourceVersion("1").
NodeOwnerReferences(ownerName, string(nodeUID)).NodeName(ownerName).
Driver(driverName).Devices([]resourceapi.Device{{Name: deviceName2}}).
Pool(resourceapi.ResourcePool{Name: poolName, Generation: 2, ResourceSliceCount: 2}).Obj(),
},
},
"delete-redundant-slice": {