You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@yunikorn.apache.org by ma...@apache.org on 2026/10/15 10:32:13 UTC
(yunikorn-core) branch master updated: [YUNIKORN-3506] Fix child queue preemptable resource calculation in quota preemption (#1189)
This is an automated email from the ASF dual-hosted git repository.
manirajv06 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-core.git
The following commit(s) were added to refs/heads/master by this push:
new 7f53db83 [YUNIKORN-3506] Fix child queue preemptable resource calculation in quota preemption (#1189)
7f53db83 is described below
commit 7f53db83f710dd5833fbf518acf700d404feae92
Author: hedger9487 <he...@gmail.com>
AuthorDate: Thu Oct 15 16:02:02 2026 +0530
[YUNIKORN-3506] Fix child queue preemptable resource calculation in quota preemption (#1189)
Closes: #1189
Signed-off-by: mani <ma...@gmail.com>
---
pkg/scheduler/objects/quota_preemptor.go | 23 +++-----
pkg/scheduler/objects/quota_preemptor_test.go | 77 +++++++++++++++++++++++++++
2 files changed, 85 insertions(+), 15 deletions(-)
diff --git a/pkg/scheduler/objects/quota_preemptor.go b/pkg/scheduler/objects/quota_preemptor.go
index da050b16..37a66bc4 100644
--- a/pkg/scheduler/objects/quota_preemptor.go
+++ b/pkg/scheduler/objects/quota_preemptor.go
@@ -165,25 +165,18 @@ func getChildQueuesPreemptableResource(queue *Queue, parentPreemptableResource *
// Total preemptable resource (sum of all children's preemptable resources) would be calculated along the way.
for _, child := range children {
allocated := child.GetAllocatedResource()
- guaranteed := child.GetGuaranteedResource()
- // Skip child if there is no usage or usage below or equals guaranteed
- if allocated.IsEmpty() || guaranteed.StrictlyGreaterThanOrEqualsOnlyExisting(allocated) {
+ if allocated.IsEmpty() {
continue
}
- var usedResource *resources.Resource
- if !guaranteed.IsEmpty() {
- usedResource = resources.SubOnlyExisting(guaranteed, allocated)
- } else {
- usedResource = allocated
- }
- preemptableResource := resources.NewResource()
- for k, v := range usedResource.Resources {
- if v < 0 {
- preemptableResource.Resources[k] = v * -1
- } else {
- preemptableResource.Resources[k] = v
+ preemptableResource := resources.SubOnlyExisting(allocated, child.GetGuaranteedResource())
+ for resourceType, v := range preemptableResource.Resources {
+ if _, ok := parentPreemptableResource.Resources[resourceType]; !ok || v <= 0 {
+ delete(preemptableResource.Resources, resourceType)
}
}
+ if preemptableResource.IsEmpty() {
+ continue
+ }
childrenPreemptableResource[child] = preemptableResource
totalPreemptableResource.AddTo(preemptableResource)
}
diff --git a/pkg/scheduler/objects/quota_preemptor_test.go b/pkg/scheduler/objects/quota_preemptor_test.go
index 03f5db0d..d4b3bba1 100644
--- a/pkg/scheduler/objects/quota_preemptor_test.go
+++ b/pkg/scheduler/objects/quota_preemptor_test.go
@@ -512,6 +512,83 @@ func TestQuotaChangeGetChildQueuesPreemptableResourceWithDifferentResTypes(t *te
}
}
+func TestGetChildQueuesPreemptableResource_UnderGuaranteedAndUnguaranteedTypes(t *testing.T) {
+ testCases := []struct {
+ name string
+ child1Guaranteed map[string]string
+ child1Allocated map[string]resources.Quantity
+ child2Guaranteed map[string]string
+ child2Allocated map[string]resources.Quantity
+ parentPreemptable map[string]resources.Quantity
+ expectedChild1 map[string]resources.Quantity
+ expectedChild2 map[string]resources.Quantity
+ }{
+ {
+ name: "under-guaranteed resource is not treated as preemptable",
+ child1Guaranteed: map[string]string{"cpu": "10", "memory": "100"},
+ child1Allocated: map[string]resources.Quantity{"cpu": 40, "memory": 20},
+ child2Guaranteed: map[string]string{"cpu": "10", "memory": "10"},
+ child2Allocated: map[string]resources.Quantity{"cpu": 40, "memory": 50},
+ parentPreemptable: map[string]resources.Quantity{"cpu": 20, "memory": 20},
+ expectedChild1: map[string]resources.Quantity{"cpu": 10},
+ expectedChild2: map[string]resources.Quantity{"cpu": 10, "memory": 20},
+ },
+ {
+ name: "unguaranteed resource type is preemptable when guaranteed is set",
+ child1Guaranteed: map[string]string{"cpu": "10"},
+ child1Allocated: map[string]resources.Quantity{"cpu": 40, "gpu": 30},
+ child2Guaranteed: map[string]string{"cpu": "10"},
+ child2Allocated: map[string]resources.Quantity{"cpu": 40, "gpu": 30},
+ parentPreemptable: map[string]resources.Quantity{"cpu": 20, "gpu": 20},
+ expectedChild1: map[string]resources.Quantity{"cpu": 10, "gpu": 10},
+ expectedChild2: map[string]resources.Quantity{"cpu": 10, "gpu": 10},
+ },
+ {
+ name: "child meeting guaranteed is not skipped when using unguaranteed resource",
+ child1Guaranteed: map[string]string{"cpu": "10"},
+ child1Allocated: map[string]resources.Quantity{"cpu": 10, "gpu": 30},
+ child2Guaranteed: map[string]string{"cpu": "10"},
+ child2Allocated: map[string]resources.Quantity{"cpu": 40, "gpu": 30},
+ parentPreemptable: map[string]resources.Quantity{"cpu": 20, "gpu": 20},
+ expectedChild1: map[string]resources.Quantity{"gpu": 10},
+ expectedChild2: map[string]resources.Quantity{"cpu": 20, "gpu": 10},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ parent, err := NewConfiguredQueue(configs.QueueConfig{Name: "parent", Parent: true}, nil, false, nil)
+ assert.NilError(t, err)
+
+ child1, err := NewConfiguredQueue(configs.QueueConfig{
+ Name: "child1",
+ Resources: configs.Resources{Guaranteed: tc.child1Guaranteed},
+ }, parent, false, nil)
+ assert.NilError(t, err)
+ child1.allocatedResource = resources.NewResourceFromMap(tc.child1Allocated)
+
+ child2, err := NewConfiguredQueue(configs.QueueConfig{
+ Name: "child2",
+ Resources: configs.Resources{Guaranteed: tc.child2Guaranteed},
+ }, parent, false, nil)
+ assert.NilError(t, err)
+ child2.allocatedResource = resources.NewResourceFromMap(tc.child2Allocated)
+
+ parentPreemptable := resources.NewResourceFromMap(tc.parentPreemptable)
+ childQueues := make(map[*Queue]*QuotaPreemptionContext)
+ getChildQueuesPreemptableResource(parent, parentPreemptable, childQueues)
+
+ expected1 := resources.NewResourceFromMap(tc.expectedChild1)
+ expected2 := resources.NewResourceFromMap(tc.expectedChild2)
+ assert.Equal(t, len(childQueues), 2)
+ assert.Assert(t, resources.Equals(childQueues[child1].preemptableResource, expected1),
+ "child1 expected %v, got %v", expected1, childQueues[child1].preemptableResource)
+ assert.Assert(t, resources.Equals(childQueues[child2].preemptableResource, expected2),
+ "child2 expected %v, got %v", expected2, childQueues[child2].preemptableResource)
+ })
+ }
+}
+
func TestQuotaChangeTryPreemptionForParentQueue(t *testing.T) {
events.Init()
eventSystem := events.GetEventSystem().(*events.EventSystemImpl) //nolint:errcheck
---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@yunikorn.apache.org
For additional commands, e-mail: issues-help@yunikorn.apache.org