This is an automated email from the ASF dual-hosted git repository.

ccondit 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 9f46b816 [YUNIKORN-2794] Resource: Change SubOnlyExisting() to same 
signature as AddOnlyExisting() (#949)
9f46b816 is described below

commit 9f46b81698a43798e87f9edaac37631b9f592a1e
Author: Tzu-Hua Lan <[email protected]>
AuthorDate: Mon Aug 19 11:30:32 2024 -0500

    [YUNIKORN-2794] Resource: Change SubOnlyExisting() to same signature as 
AddOnlyExisting() (#949)
    
    Closes: #949
    
    Signed-off-by: Craig Condit <[email protected]>
---
 pkg/common/resources/resources.go      | 16 ++++----
 pkg/common/resources/resources_test.go | 72 +++++++++++++++-------------------
 pkg/scheduler/objects/application.go   |  4 +-
 pkg/scheduler/objects/preemption.go    | 21 ++++------
 pkg/scheduler/objects/queue.go         |  4 +-
 pkg/scheduler/ugm/queue_tracker.go     |  3 +-
 6 files changed, 53 insertions(+), 67 deletions(-)

diff --git a/pkg/common/resources/resources.go 
b/pkg/common/resources/resources.go
index c5bc7c54..0f6083ff 100644
--- a/pkg/common/resources/resources.go
+++ b/pkg/common/resources/resources.go
@@ -363,18 +363,18 @@ func Sub(left, right *Resource) *Resource {
        return out
 }
 
-// SubOnlyExisting subtract delta from defined resource.
-// Ignore any type not defined in the base resource (ie receiver).
-// Used as part of the headroom updates as undefined resources are unlimited
-func (r *Resource) SubOnlyExisting(delta *Resource) {
+// SubOnlyExisting subtracts delta from base resource, ignoring any type not 
defined in the base resource.
+func SubOnlyExisting(base, delta *Resource) *Resource {
        // check nil inputs and shortcut
-       if r == nil || delta == nil {
-               return
+       if base == nil || delta == nil {
+               return base.Clone()
        }
        // neither are nil, subtract the delta
-       for k := range r.Resources {
-               r.Resources[k] = subVal(r.Resources[k], delta.Resources[k])
+       result := NewResource()
+       for k := range base.Resources {
+               result.Resources[k] = subVal(base.Resources[k], 
delta.Resources[k])
        }
+       return result
 }
 
 // AddOnlyExisting adds delta to base resource, ignoring any type not defined 
in the base resource.
diff --git a/pkg/common/resources/resources_test.go 
b/pkg/common/resources/resources_test.go
index 88c2c421..1cfe3500 100644
--- a/pkg/common/resources/resources_test.go
+++ b/pkg/common/resources/resources_test.go
@@ -1058,20 +1058,6 @@ func TestSubFrom(t *testing.T) {
        }
 }
 
-func TestSubOnlyExistingNil(t *testing.T) {
-       // simple case (nil checks)
-       defer func() {
-               if r := recover(); r != nil {
-                       t.Fatal("SubOnlyExisting panic on nil resource")
-               }
-       }()
-       var r *Resource
-       r.SubOnlyExisting(nil)
-       if r != nil {
-               t.Errorf("sub nil resources did not return nil resource: %v", r)
-       }
-}
-
 func TestSubEliminateNegative(t *testing.T) {
        // simple case (nil checks)
        result := SubEliminateNegative(nil, nil)
@@ -1081,32 +1067,38 @@ func TestSubEliminateNegative(t *testing.T) {
 }
 
 func TestSubOnlyExisting(t *testing.T) {
-       // remove nil from empty resource
-       left := NewResource()
-       left.SubOnlyExisting(nil)
-       assert.Equal(t, len(left.Resources), 0, "sub nil resource did not 
return unchanged resource")
-
-       // remove from empty resource
-       delta := NewResourceFromMap(map[string]Quantity{"a": 5})
-       left.SubOnlyExisting(delta)
-       assert.Equal(t, len(left.Resources), 0, "sub simple resource did not 
return unchanged resource")
-
-       // complex case: just checking the resource merge, values check is 
secondary
-       left = &Resource{Resources: map[string]Quantity{"a": 0}}
-       delta = &Resource{Resources: map[string]Quantity{"a": 1, "b": 0}}
-       left.SubOnlyExisting(delta)
-       expected := &Resource{Resources: map[string]Quantity{"a": -1}}
-       assert.Equal(t, len(left.Resources), 1, "sub with 1 resource returned 
more or less types")
-       assert.Assert(t, Equals(left, expected), "sub failed expected %v, 
actual %v", expected, left)
-
-       // complex case: just checking the resource merge, values check is 
secondary
-       left = &Resource{Resources: map[string]Quantity{"a": 1, "b": 0}}
-       delta = &Resource{Resources: map[string]Quantity{"a": 1}}
-       left.SubOnlyExisting(delta)
-       assert.Equal(t, len(left.Resources), 2, "sub with 2 resource returned 
more or less types")
-
-       expected = &Resource{Resources: map[string]Quantity{"a": 0, "b": 0}}
-       assert.Assert(t, Equals(left, expected), "sub failed expected %v, 
actual %v", expected, left)
+       var tests = []struct {
+               caseName string
+               base     map[string]Quantity
+               delta    map[string]Quantity
+               expected map[string]Quantity
+       }{
+               {"nil resources", nil, nil, nil},
+               {"nil base", nil, map[string]Quantity{"a": 5}, nil},
+               {"nil delta", map[string]Quantity{"a": 5}, nil, 
map[string]Quantity{"a": 5}},
+               {"empty base", map[string]Quantity{}, map[string]Quantity{"a": 
5}, map[string]Quantity{}},
+               {"single type base matched", map[string]Quantity{"a": 5}, 
map[string]Quantity{"a": 3, "b": 1}, map[string]Quantity{"a": 2}},
+               {"single type base unmatched", map[string]Quantity{"a": 5}, 
map[string]Quantity{"b": 1}, map[string]Quantity{"a": 5}},
+               {"multi type base partial match", map[string]Quantity{"a": 5, 
"b": 3}, map[string]Quantity{"a": 2, "c": 1}, map[string]Quantity{"a": 3, "b": 
3}},
+               {"multi type base match", map[string]Quantity{"a": 5, "b": 3}, 
map[string]Quantity{"a": 2, "b": 1}, map[string]Quantity{"a": 3, "b": 2}},
+               {"negative result", map[string]Quantity{"a": 1}, 
map[string]Quantity{"a": 3}, map[string]Quantity{"a": -2}},
+       }
+       for _, tt := range tests {
+               t.Run(tt.caseName, func(t *testing.T) {
+                       var base, delta, expected *Resource
+                       if tt.base != nil {
+                               base = NewResourceFromMap(tt.base)
+                       }
+                       if tt.delta != nil {
+                               delta = NewResourceFromMap(tt.delta)
+                       }
+                       if tt.expected != nil {
+                               expected = NewResourceFromMap(tt.expected)
+                       }
+                       result := SubOnlyExisting(base, delta)
+                       assert.Assert(t, Equals(result, expected), "incorrect 
result returned")
+               })
+       }
 }
 
 func TestAddOnlyExisting(t *testing.T) {
diff --git a/pkg/scheduler/objects/application.go 
b/pkg/scheduler/objects/application.go
index b796f831..1ccde74e 100644
--- a/pkg/scheduler/objects/application.go
+++ b/pkg/scheduler/objects/application.go
@@ -926,8 +926,8 @@ func (sa *Application) getOutstandingRequests(headRoom 
*resources.Resource, user
                                // if headroom is still enough for the resources
                                *total = append(*total, request)
                        }
-                       headRoom.SubOnlyExisting(request.GetAllocatedResource())
-                       
userHeadRoom.SubOnlyExisting(request.GetAllocatedResource())
+                       headRoom = resources.SubOnlyExisting(headRoom, 
request.GetAllocatedResource())
+                       userHeadRoom = resources.SubOnlyExisting(userHeadRoom, 
request.GetAllocatedResource())
                }
        }
 }
diff --git a/pkg/scheduler/objects/preemption.go 
b/pkg/scheduler/objects/preemption.go
index 6b00edab..40190fe4 100644
--- a/pkg/scheduler/objects/preemption.go
+++ b/pkg/scheduler/objects/preemption.go
@@ -768,21 +768,17 @@ func (qps *QueuePreemptionSnapshot) Duplicate(copy 
map[string]*QueuePreemptionSn
 }
 
 func (qps *QueuePreemptionSnapshot) GetPreemptableResource() 
*resources.Resource {
-       if qps == nil {
-               return nil
-       }
-       parentPreemptableResource := qps.Parent.GetPreemptableResource()
-       actual := qps.AllocatedResource.Clone()
-
        // No usage, so nothing to preempt
-       if actual.IsEmpty() {
+       if qps == nil || qps.AllocatedResource.IsEmpty() {
                return nil
        }
-       actual.SubOnlyExisting(qps.PreemptingResource)
+
+       parentPreemptableResource := qps.Parent.GetPreemptableResource()
+       actual := resources.SubOnlyExisting(qps.AllocatedResource, 
qps.PreemptingResource)
 
        // Calculate preemptable resource. +ve means Over utilized, -ve means 
Under utilized, 0 means correct utilization
        guaranteed := qps.GuaranteedResource
-       actual.SubOnlyExisting(guaranteed)
+       actual = resources.SubOnlyExisting(actual, guaranteed)
        preemptableResource := actual
 
        // Keep only the resource type which needs to be preempted
@@ -815,7 +811,7 @@ func (qps *QueuePreemptionSnapshot) 
GetRemainingGuaranteedResource() *resources.
                return nil
        }
        parent := qps.Parent.GetRemainingGuaranteedResource()
-       remainingGuaranteed := qps.GuaranteedResource.Clone()
+       remainingGuaranteed := qps.GuaranteedResource
 
        // No Guaranteed set, so nothing remaining
        // In case of guaranteed not set for queues at specific level, inherits 
the same from parent queue.
@@ -824,9 +820,8 @@ func (qps *QueuePreemptionSnapshot) 
GetRemainingGuaranteedResource() *resources.
        if parent.IsEmpty() && remainingGuaranteed.IsEmpty() {
                return nil
        }
-       used := qps.AllocatedResource.Clone()
-       used.SubOnlyExisting(qps.PreemptingResource)
-       remainingGuaranteed.SubOnlyExisting(used)
+       used := resources.SubOnlyExisting(qps.AllocatedResource, 
qps.PreemptingResource)
+       remainingGuaranteed = resources.SubOnlyExisting(remainingGuaranteed, 
used)
        if qps.AskQueue != nil {
                // In case ask queue has guaranteed set, its own values carries 
higher precedence over the parent or ancestor
                if qps.AskQueue.QueuePath == qps.QueuePath && 
!remainingGuaranteed.IsEmpty() {
diff --git a/pkg/scheduler/objects/queue.go b/pkg/scheduler/objects/queue.go
index 2a277eb6..dd13b22b 100644
--- a/pkg/scheduler/objects/queue.go
+++ b/pkg/scheduler/objects/queue.go
@@ -1208,7 +1208,7 @@ func (sq *Queue) getMaxHeadRoom() *resources.Resource {
 func (sq *Queue) internalHeadRoom(parentHeadRoom *resources.Resource) 
*resources.Resource {
        sq.RLock()
        defer sq.RUnlock()
-       headRoom := sq.maxResource.Clone()
+       headRoom := sq.maxResource
 
        // if we have no max set headroom is always the same as the parent
        if headRoom == nil {
@@ -1217,7 +1217,7 @@ func (sq *Queue) internalHeadRoom(parentHeadRoom 
*resources.Resource) *resources
 
        // calculate what we have left over after removing all allocation
        // ignore unlimited resource types (ie the ones not defined in max)
-       headRoom.SubOnlyExisting(sq.allocatedResource)
+       headRoom = resources.SubOnlyExisting(headRoom, sq.allocatedResource)
 
        // check the minimum of the two: parentHeadRoom is nil for root
        if parentHeadRoom == nil {
diff --git a/pkg/scheduler/ugm/queue_tracker.go 
b/pkg/scheduler/ugm/queue_tracker.go
index 9e77c098..d4e1d373 100644
--- a/pkg/scheduler/ugm/queue_tracker.go
+++ b/pkg/scheduler/ugm/queue_tracker.go
@@ -219,8 +219,7 @@ func (qt *QueueTracker) headroom(hierarchy []string, 
trackType trackingType) *re
 
        // arrived at the leaf or on the way out: check against current max if 
set
        if !resources.IsZero(qt.maxResources) {
-               headroom = qt.maxResources.Clone()
-               headroom.SubOnlyExisting(qt.resourceUsage)
+               headroom = resources.SubOnlyExisting(qt.maxResources, 
qt.resourceUsage)
        }
 
        if headroom == nil {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to