diff --git a/pkg/scheduler/plugins/elasticquota/core/group_quota_manager.go b/pkg/scheduler/plugins/elasticquota/core/group_quota_manager.go index 5310e746f..6036a7edb 100644 --- a/pkg/scheduler/plugins/elasticquota/core/group_quota_manager.go +++ b/pkg/scheduler/plugins/elasticquota/core/group_quota_manager.go @@ -185,7 +185,8 @@ func (gqm *GroupQuotaManager) recursiveUpdateGroupTreeWithDeltaRequest(deltaReq, for i := 0; i < len(curToAllParInfos); i++ { curQuotaInfo := curToAllParInfos[i] oldSubLimitReq := curQuotaInfo.getLimitRequestNoLock() - curQuotaInfo.addRequestNonNegativeNoLock(deltaReq, deltaNonPreemptibleRequest) + isSelfRequest := i == 0 + curQuotaInfo.addRequestNonNegativeNoLock(deltaReq, deltaNonPreemptibleRequest, isSelfRequest) if curQuotaInfo.Name == extension.RootQuotaName { return } @@ -234,7 +235,8 @@ func (gqm *GroupQuotaManager) updateGroupDeltaUsedNoLock(quotaName string, delta defer gqm.scopedLockForQuotaInfo(curToAllParInfos)() for i := 0; i < allQuotaInfoLen; i++ { quotaInfo := curToAllParInfos[i] - quotaInfo.addUsedNonNegativeNoLock(delta, deltaNonPreemptibleUsed) + isSelfUsed := i == 0 + quotaInfo.addUsedNonNegativeNoLock(delta, deltaNonPreemptibleUsed, isSelfUsed) } if utilfeature.DefaultFeatureGate.Enabled(features.ElasticQuotaGuaranteeUsage) { @@ -338,7 +340,7 @@ func (gqm *GroupQuotaManager) getCurToAllParentGroupQuotaInfoNoLock(quotaName st return curToAllParInfos } - for true { + for { curToAllParInfos = append(curToAllParInfos, quotaInfo) if quotaInfo.Name == extension.RootQuotaName { break @@ -472,7 +474,7 @@ func (gqm *GroupQuotaManager) buildSubParGroupTopoNoLock() { // ResetAllGroupQuotaNoLock no need to lock gqm.lock func (gqm *GroupQuotaManager) resetAllGroupQuotaNoLock() { - childRequestMap, childNonPreemptibleUsedMap, childUsedMap, childNonPreemptibleRequestMap := + toUpdateRequestMap, toUpdateNonPreemptibleUsedMap, toUpdateUsedMap, toUpdateNonPreemptibleRequestMap := make(quotaResMapType), make(quotaResMapType), make(quotaResMapType), make(quotaResMapType) for quotaName, topoNode := range gqm.quotaTopoNodeMap { if quotaName == extension.RootQuotaName { @@ -481,10 +483,15 @@ func (gqm *GroupQuotaManager) resetAllGroupQuotaNoLock() { } topoNode.quotaInfo.lock.Lock() if !topoNode.quotaInfo.IsParent { - childRequestMap[quotaName] = topoNode.quotaInfo.CalculateInfo.ChildRequest.DeepCopy() - childNonPreemptibleRequestMap[quotaName] = topoNode.quotaInfo.CalculateInfo.NonPreemptibleRequest.DeepCopy() - childNonPreemptibleUsedMap[quotaName] = topoNode.quotaInfo.CalculateInfo.NonPreemptibleUsed.DeepCopy() - childUsedMap[quotaName] = topoNode.quotaInfo.CalculateInfo.Used.DeepCopy() + toUpdateRequestMap[quotaName] = topoNode.quotaInfo.CalculateInfo.ChildRequest.DeepCopy() + toUpdateNonPreemptibleRequestMap[quotaName] = topoNode.quotaInfo.CalculateInfo.NonPreemptibleRequest.DeepCopy() + toUpdateNonPreemptibleUsedMap[quotaName] = topoNode.quotaInfo.CalculateInfo.NonPreemptibleUsed.DeepCopy() + toUpdateUsedMap[quotaName] = topoNode.quotaInfo.CalculateInfo.Used.DeepCopy() + } else { + toUpdateRequestMap[quotaName] = topoNode.quotaInfo.CalculateInfo.ParentSelfRequest.DeepCopy() + toUpdateNonPreemptibleRequestMap[quotaName] = topoNode.quotaInfo.CalculateInfo.ParentSelfNonPreemptibleRequest.DeepCopy() + toUpdateNonPreemptibleUsedMap[quotaName] = topoNode.quotaInfo.CalculateInfo.ParentSelfNonPreemptibleUsed.DeepCopy() + toUpdateUsedMap[quotaName] = topoNode.quotaInfo.CalculateInfo.ParentSelfUsed.DeepCopy() } topoNode.quotaInfo.clearForResetNoLock() topoNode.quotaInfo.lock.Unlock() @@ -501,9 +508,9 @@ func (gqm *GroupQuotaManager) resetAllGroupQuotaNoLock() { // subGroup's topo relation may change; refresh the request/used from bottom to top for quotaName, topoNode := range gqm.quotaTopoNodeMap { - if !topoNode.quotaInfo.IsParent { - gqm.updateGroupDeltaRequestNoLock(quotaName, childRequestMap[quotaName], childNonPreemptibleRequestMap[quotaName]) - gqm.updateGroupDeltaUsedNoLock(quotaName, childUsedMap[quotaName], childNonPreemptibleUsedMap[quotaName]) + if _, ok := toUpdateRequestMap[topoNode.quotaInfo.Name]; ok { + gqm.updateGroupDeltaRequestNoLock(quotaName, toUpdateRequestMap[quotaName], toUpdateNonPreemptibleRequestMap[quotaName]) + gqm.updateGroupDeltaUsedNoLock(quotaName, toUpdateUsedMap[quotaName], toUpdateNonPreemptibleUsedMap[quotaName]) } } } diff --git a/pkg/scheduler/plugins/elasticquota/core/group_quota_manager_test.go b/pkg/scheduler/plugins/elasticquota/core/group_quota_manager_test.go index a61dfd62a..260492fdb 100644 --- a/pkg/scheduler/plugins/elasticquota/core/group_quota_manager_test.go +++ b/pkg/scheduler/plugins/elasticquota/core/group_quota_manager_test.go @@ -443,6 +443,8 @@ func TestGroupQuotaManager_UpdateGroupDeltaUsedAndNonPreemptibleUsed(t *testing. assert.NotNil(t, quotaInfo) assert.Equal(t, used, quotaInfo.CalculateInfo.Used) assert.Equal(t, nonPreemptibleUsed, quotaInfo.CalculateInfo.NonPreemptibleUsed) + assert.Equal(t, nonPreemptibleUsed, quotaInfo.CalculateInfo.ParentSelfNonPreemptibleUsed) + assert.Equal(t, nonPreemptibleUsed, quotaInfo.CalculateInfo.ParentSelfUsed) // 2. used increases to [130,300] used = createResourceList(10, 10*GigaByte) @@ -452,6 +454,8 @@ func TestGroupQuotaManager_UpdateGroupDeltaUsedAndNonPreemptibleUsed(t *testing. assert.NotNil(t, quotaInfo) assert.Equal(t, createResourceList(130, 300*GigaByte), quotaInfo.CalculateInfo.Used) assert.Equal(t, createResourceList(30, 40*GigaByte), quotaInfo.CalculateInfo.NonPreemptibleUsed) + assert.Equal(t, createResourceList(130, 300*GigaByte), quotaInfo.CalculateInfo.ParentSelfUsed) + assert.Equal(t, createResourceList(30, 40*GigaByte), quotaInfo.CalculateInfo.ParentSelfNonPreemptibleUsed) // 3. used decreases to [90,100] used = createResourceList(-40, -200*GigaByte) @@ -461,6 +465,8 @@ func TestGroupQuotaManager_UpdateGroupDeltaUsedAndNonPreemptibleUsed(t *testing. assert.NotNil(t, quotaInfo) assert.Equal(t, createResourceList(90, 100*GigaByte), quotaInfo.CalculateInfo.Used) assert.Equal(t, createResourceList(15, 20*GigaByte), quotaInfo.CalculateInfo.NonPreemptibleUsed) + assert.Equal(t, createResourceList(90, 100*GigaByte), quotaInfo.CalculateInfo.ParentSelfUsed) + assert.Equal(t, createResourceList(15, 20*GigaByte), quotaInfo.CalculateInfo.ParentSelfNonPreemptibleUsed) } func TestGroupQuotaManager_MultiQuotaAdd(t *testing.T) { @@ -797,6 +803,24 @@ func TestGroupQuotaManager_UpdateQuotaParentName(t *testing.T) { request := createResourceList(60, 100*GigaByte) gqm.updateGroupDeltaRequestNoLock("a-123", request, request) gqm.updateGroupDeltaUsedNoLock("a-123", request, createResourceList(0, 0)) + qi1 := gqm.GetQuotaInfoByName("test1") + qi2 := gqm.GetQuotaInfoByName("test1-a") + qi3 := gqm.GetQuotaInfoByName("a-123") + qi4 := gqm.GetQuotaInfoByName("test2") + qi5 := gqm.GetQuotaInfoByName("test2-a") + assert.Equal(t, request, qi1.CalculateInfo.Request) + assert.Equal(t, request, qi1.CalculateInfo.Used) + assert.Equal(t, request, qi2.CalculateInfo.Request) + assert.Equal(t, request, qi2.CalculateInfo.Used) + assert.Equal(t, request, qi3.CalculateInfo.ParentSelfRequest) + assert.Equal(t, request, qi3.CalculateInfo.ParentSelfUsed) + assert.Equal(t, v1.ResourceList{}, qi1.CalculateInfo.ParentSelfRequest) + assert.Equal(t, v1.ResourceList{}, qi1.CalculateInfo.ParentSelfUsed) + assert.Equal(t, v1.ResourceList{}, qi2.CalculateInfo.ParentSelfRequest) + assert.Equal(t, v1.ResourceList{}, qi2.CalculateInfo.ParentSelfUsed) + assert.Equal(t, request, qi3.CalculateInfo.ParentSelfRequest) + assert.Equal(t, request, qi3.CalculateInfo.ParentSelfUsed) + runtime := gqm.RefreshRuntime("a-123") assert.Equal(t, request, runtime) @@ -810,6 +834,15 @@ func TestGroupQuotaManager_UpdateQuotaParentName(t *testing.T) { request = createResourceList(20, 40*GigaByte) gqm.updateGroupDeltaRequestNoLock("test2-a", request, request) gqm.updateGroupDeltaUsedNoLock("test2-a", request, createResourceList(0, 0)) + assert.Equal(t, request, qi4.CalculateInfo.Request) + assert.Equal(t, request, qi4.CalculateInfo.Used) + assert.Equal(t, request, qi5.CalculateInfo.Request) + assert.Equal(t, request, qi5.CalculateInfo.Used) + assert.Equal(t, v1.ResourceList{}, qi4.CalculateInfo.ParentSelfRequest) + assert.Equal(t, v1.ResourceList{}, qi4.CalculateInfo.ParentSelfUsed) + assert.Equal(t, request, qi5.CalculateInfo.ParentSelfRequest) + assert.Equal(t, request, qi5.CalculateInfo.ParentSelfUsed) + runtime = gqm.RefreshRuntime("test2-a") assert.Equal(t, request, runtime) @@ -1373,15 +1406,23 @@ func TestGroupQuotaManager_UpdatePodCache_UpdatePodIsAssigned_GetPodIsAssigned_U gqm.updatePodRequestNoLock("1", nil, pod1) assert.Equal(t, createResourceList(10, 10), gqm.GetQuotaInfoByName("1").GetRequest()) assert.Equal(t, createResourceList(10, 10), gqm.GetQuotaInfoByName("1").GetNonPreemptibleRequest()) + assert.Equal(t, createResourceList(10, 10), gqm.GetQuotaInfoByName("1").GetParentSelfRequest()) + assert.Equal(t, createResourceList(10, 10), gqm.GetQuotaInfoByName("1").GetParentSelfNonPreemptibleRequest()) gqm.updatePodUsedNoLock("2", nil, pod1) assert.Equal(t, createResourceList(10, 10), gqm.GetQuotaInfoByName("2").GetUsed()) assert.Equal(t, createResourceList(10, 10), gqm.GetQuotaInfoByName("2").GetNonPreemptibleUsed()) + assert.Equal(t, createResourceList(10, 10), gqm.GetQuotaInfoByName("2").GetParentSelfUsed()) + assert.Equal(t, createResourceList(10, 10), gqm.GetQuotaInfoByName("2").GetParentSelfNonPreemptibleUsed()) gqm.updatePodRequestNoLock("1", pod1, nil) assert.Equal(t, createResourceList(0, 0), gqm.GetQuotaInfoByName("1").GetRequest()) assert.Equal(t, createResourceList(0, 0), gqm.GetQuotaInfoByName("1").GetNonPreemptibleRequest()) + assert.Equal(t, createResourceList(0, 0), gqm.GetQuotaInfoByName("1").GetParentSelfRequest()) + assert.Equal(t, createResourceList(0, 0), gqm.GetQuotaInfoByName("1").GetParentSelfNonPreemptibleRequest()) gqm.updatePodUsedNoLock("2", pod1, nil) assert.Equal(t, createResourceList(0, 0), gqm.GetQuotaInfoByName("2").GetUsed()) assert.Equal(t, createResourceList(0, 0), gqm.GetQuotaInfoByName("2").GetNonPreemptibleUsed()) + assert.Equal(t, createResourceList(0, 0), gqm.GetQuotaInfoByName("2").GetParentSelfUsed()) + assert.Equal(t, createResourceList(0, 0), gqm.GetQuotaInfoByName("2").GetParentSelfNonPreemptibleUsed()) } func TestGroupQuotaManager_OnPodUpdate(t *testing.T) { @@ -1839,3 +1880,50 @@ func TestUpdateQuotaInternalNoLock(t *testing.T) { assert.Equal(t, createResourceList(25, 25), gqm.GetQuotaInfoByName("1").GetAllocated()) assert.Equal(t, createResourceList(25, 25), gqm.GetQuotaInfoByName("1").GetGuaranteed()) } + +func TestUpdateQuotaInternalNoLock_ParenstSelf(t *testing.T) { + gqm := NewGroupQuotaManagerForTest() + gqm.scaleMinQuotaEnabled = true + gqm.UpdateClusterTotalResource(createResourceList(50, 50)) + + // quota1 Max[40, 40] Min[20,20] request[0,0] + // |-- quota2 Max[30, 20] Min[10,10] request[0,0] + // |-- quota3 Max[20, 10] Min[5,5] request[0,0] + eq1 := createQuota("1", extension.RootQuotaName, 40, 40, 20, 20) + eq2 := createQuota("2", "1", 30, 10, 10, 10) + eq3 := createQuota("3", "1", 20, 10, 5, 5) + eq4 := createQuota("4", "2", 30, 10, 10, 10) + gqm.UpdateQuota(eq1, false) + gqm.UpdateQuota(eq2, false) + gqm.UpdateQuota(eq3, false) + gqm.UpdateQuota(eq4, false) + + qi1, qi2, qi3, qi4 := gqm.GetQuotaInfoByName(eq1.Name), gqm.GetQuotaInfoByName(eq2.Name), gqm.GetQuotaInfoByName(eq3.Name), gqm.GetQuotaInfoByName(eq4.Name) + + qi2.CalculateInfo.ParentSelfRequest = createResourceList(20, 20) + qi3.CalculateInfo.ChildRequest = createResourceList(20, 20) + qi4.CalculateInfo.ChildRequest = createResourceList(20, 20) + qi2.CalculateInfo.ParentSelfNonPreemptibleRequest = createResourceList(10, 10) + qi3.CalculateInfo.NonPreemptibleRequest = createResourceList(5, 5) + qi4.CalculateInfo.NonPreemptibleRequest = createResourceList(10, 10) + + gqm.updateQuotaGroupConfigNoLock() + + assert.Equal(t, createResourceList(10, 10), qi4.CalculateInfo.ParentSelfNonPreemptibleRequest) + assert.Equal(t, createResourceList(20, 20), qi4.CalculateInfo.ParentSelfRequest) + assert.Equal(t, createResourceList(5, 5), qi3.CalculateInfo.ParentSelfNonPreemptibleRequest) + assert.Equal(t, createResourceList(20, 20), qi3.CalculateInfo.ParentSelfRequest) + assert.Equal(t, createResourceList(10, 10), qi2.CalculateInfo.ParentSelfNonPreemptibleRequest) + assert.Equal(t, createResourceList(20, 20), qi2.CalculateInfo.ParentSelfRequest) + assert.Equal(t, v1.ResourceList{}, qi1.CalculateInfo.ParentSelfNonPreemptibleRequest) + assert.Equal(t, v1.ResourceList{}, qi1.CalculateInfo.ParentSelfRequest) + + assert.Equal(t, createResourceList(10, 10), qi4.CalculateInfo.NonPreemptibleRequest) + assert.Equal(t, createResourceList(20, 20), qi4.CalculateInfo.Request) + assert.Equal(t, createResourceList(5, 5), qi3.CalculateInfo.NonPreemptibleRequest) + assert.Equal(t, createResourceList(20, 20), qi3.CalculateInfo.Request) + assert.Equal(t, createResourceList(20, 20), qi2.CalculateInfo.NonPreemptibleRequest) + assert.Equal(t, createResourceList(40, 30), qi2.CalculateInfo.Request) + assert.Equal(t, createResourceList(25, 25), qi1.CalculateInfo.NonPreemptibleRequest) + assert.Equal(t, createResourceList(50, 20), qi1.CalculateInfo.Request) +} diff --git a/pkg/scheduler/plugins/elasticquota/core/quota_info.go b/pkg/scheduler/plugins/elasticquota/core/quota_info.go index da4ed4ec0..a18bc2baf 100644 --- a/pkg/scheduler/plugins/elasticquota/core/quota_info.go +++ b/pkg/scheduler/plugins/elasticquota/core/quota_info.go @@ -49,7 +49,11 @@ type QuotaCalculateInfo struct { NonPreemptibleRequest v1.ResourceList // ChildRquest is the sum of child quota requests. // If the quota is leaf, it's the sum of pods requests - ChildRequest v1.ResourceList + ChildRequest v1.ResourceList + ParentSelfRequest v1.ResourceList + ParentSelfUsed v1.ResourceList + ParentSelfNonPreemptibleUsed v1.ResourceList + ParentSelfNonPreemptibleRequest v1.ResourceList // SharedWeight determines the ability of quota groups to compete for shared resources SharedWeight v1.ResourceList // Runtime is the current actual resource that can be used by the quota group @@ -88,18 +92,22 @@ func NewQuotaInfo(isParent, allowLentResource bool, name, parentName string) *Qu RuntimeVersion: 0, PodCache: make(map[string]*PodInfo), CalculateInfo: QuotaCalculateInfo{ - Max: v1.ResourceList{}, - AutoScaleMin: v1.ResourceList{}, - Min: v1.ResourceList{}, - Used: v1.ResourceList{}, - NonPreemptibleUsed: v1.ResourceList{}, - Request: v1.ResourceList{}, - NonPreemptibleRequest: v1.ResourceList{}, - SharedWeight: v1.ResourceList{}, - Runtime: v1.ResourceList{}, - ChildRequest: v1.ResourceList{}, - Guaranteed: v1.ResourceList{}, - Allocated: v1.ResourceList{}, + Max: v1.ResourceList{}, + AutoScaleMin: v1.ResourceList{}, + Min: v1.ResourceList{}, + Used: v1.ResourceList{}, + NonPreemptibleUsed: v1.ResourceList{}, + Request: v1.ResourceList{}, + NonPreemptibleRequest: v1.ResourceList{}, + SharedWeight: v1.ResourceList{}, + Runtime: v1.ResourceList{}, + ChildRequest: v1.ResourceList{}, + Guaranteed: v1.ResourceList{}, + Allocated: v1.ResourceList{}, + ParentSelfRequest: v1.ResourceList{}, + ParentSelfUsed: v1.ResourceList{}, + ParentSelfNonPreemptibleRequest: v1.ResourceList{}, + ParentSelfNonPreemptibleUsed: v1.ResourceList{}, }, } } @@ -119,18 +127,22 @@ func (qi *QuotaInfo) DeepCopy() *QuotaInfo { RuntimeVersion: qi.RuntimeVersion, PodCache: make(map[string]*PodInfo), CalculateInfo: QuotaCalculateInfo{ - Max: qi.CalculateInfo.Max.DeepCopy(), - AutoScaleMin: qi.CalculateInfo.AutoScaleMin.DeepCopy(), - Min: qi.CalculateInfo.Min.DeepCopy(), - Used: qi.CalculateInfo.Used.DeepCopy(), - NonPreemptibleUsed: qi.CalculateInfo.NonPreemptibleUsed.DeepCopy(), - Request: qi.CalculateInfo.Request.DeepCopy(), - NonPreemptibleRequest: qi.CalculateInfo.NonPreemptibleRequest.DeepCopy(), - SharedWeight: qi.CalculateInfo.SharedWeight.DeepCopy(), - Runtime: qi.CalculateInfo.Runtime.DeepCopy(), - ChildRequest: qi.CalculateInfo.ChildRequest.DeepCopy(), - Guaranteed: qi.CalculateInfo.Guaranteed.DeepCopy(), - Allocated: qi.CalculateInfo.Allocated.DeepCopy(), + Max: qi.CalculateInfo.Max.DeepCopy(), + AutoScaleMin: qi.CalculateInfo.AutoScaleMin.DeepCopy(), + Min: qi.CalculateInfo.Min.DeepCopy(), + Used: qi.CalculateInfo.Used.DeepCopy(), + NonPreemptibleUsed: qi.CalculateInfo.NonPreemptibleUsed.DeepCopy(), + Request: qi.CalculateInfo.Request.DeepCopy(), + NonPreemptibleRequest: qi.CalculateInfo.NonPreemptibleRequest.DeepCopy(), + SharedWeight: qi.CalculateInfo.SharedWeight.DeepCopy(), + Runtime: qi.CalculateInfo.Runtime.DeepCopy(), + ChildRequest: qi.CalculateInfo.ChildRequest.DeepCopy(), + Guaranteed: qi.CalculateInfo.Guaranteed.DeepCopy(), + Allocated: qi.CalculateInfo.Allocated.DeepCopy(), + ParentSelfRequest: qi.CalculateInfo.ParentSelfRequest.DeepCopy(), + ParentSelfUsed: qi.CalculateInfo.ParentSelfUsed.DeepCopy(), + ParentSelfNonPreemptibleRequest: qi.CalculateInfo.ParentSelfNonPreemptibleRequest.DeepCopy(), + ParentSelfNonPreemptibleUsed: qi.CalculateInfo.ParentSelfNonPreemptibleUsed.DeepCopy(), }, } for name, pod := range qi.PodCache { @@ -162,6 +174,10 @@ func (qi *QuotaInfo) GetQuotaSummary(treeID string, includePods bool) *QuotaInfo quotaInfoSummary.ChildRequest = qi.CalculateInfo.ChildRequest.DeepCopy() quotaInfoSummary.Allocated = qi.CalculateInfo.Allocated.DeepCopy() quotaInfoSummary.Guaranteed = qi.CalculateInfo.Guaranteed.DeepCopy() + quotaInfoSummary.ParentSelfUsed = qi.CalculateInfo.ParentSelfUsed.DeepCopy() + quotaInfoSummary.ParentSelfRequest = qi.CalculateInfo.ParentSelfRequest.DeepCopy() + quotaInfoSummary.ParentSelfNonPreemptibleUsed = qi.CalculateInfo.ParentSelfNonPreemptibleUsed.DeepCopy() + quotaInfoSummary.ParentSelfNonPreemptibleRequest = qi.CalculateInfo.ParentSelfNonPreemptibleRequest.DeepCopy() if includePods { for podName, podInfo := range qi.PodCache { @@ -219,7 +235,7 @@ func (qi *QuotaInfo) setMinNoLock(min v1.ResourceList) { qi.CalculateInfo.Min = min.DeepCopy() } -func (qi *QuotaInfo) addRequestNonNegativeNoLock(delta, deltaNonPreemptibleRequest v1.ResourceList) { +func (qi *QuotaInfo) addRequestNonNegativeNoLock(delta, deltaNonPreemptibleRequest v1.ResourceList, isSelfRequest bool) { qi.CalculateInfo.Request = quotav1.Add(qi.CalculateInfo.Request, delta) for _, resName := range quotav1.IsNegative(qi.CalculateInfo.Request) { qi.CalculateInfo.Request[resName] = createQuantity(0, resName) @@ -228,6 +244,17 @@ func (qi *QuotaInfo) addRequestNonNegativeNoLock(delta, deltaNonPreemptibleReque for _, resName := range quotav1.IsNegative(qi.CalculateInfo.NonPreemptibleRequest) { qi.CalculateInfo.NonPreemptibleRequest[resName] = createQuantity(0, resName) } + + if isSelfRequest { + qi.CalculateInfo.ParentSelfRequest = quotav1.Add(qi.CalculateInfo.ParentSelfRequest, delta) + for _, resName := range quotav1.IsNegative(qi.CalculateInfo.ParentSelfRequest) { + qi.CalculateInfo.ParentSelfRequest[resName] = createQuantity(0, resName) + } + qi.CalculateInfo.ParentSelfNonPreemptibleRequest = quotav1.Add(qi.CalculateInfo.ParentSelfNonPreemptibleRequest, deltaNonPreemptibleRequest) + for _, resName := range quotav1.IsNegative(qi.CalculateInfo.ParentSelfNonPreemptibleRequest) { + qi.CalculateInfo.ParentSelfNonPreemptibleRequest[resName] = createQuantity(0, resName) + } + } } func (qi *QuotaInfo) addChildRequestNonNegativeNoLock(delta v1.ResourceList) { @@ -249,7 +276,7 @@ func (qi *QuotaInfo) GetAllocated() v1.ResourceList { return qi.CalculateInfo.Allocated.DeepCopy() } -func (qi *QuotaInfo) addUsedNonNegativeNoLock(delta, deltaNonPreemptibleUsed v1.ResourceList) { +func (qi *QuotaInfo) addUsedNonNegativeNoLock(delta, deltaNonPreemptibleUsed v1.ResourceList, isSelfUsed bool) { qi.CalculateInfo.Used = quotav1.Add(qi.CalculateInfo.Used, delta) qi.CalculateInfo.NonPreemptibleUsed = quotav1.Add(qi.CalculateInfo.NonPreemptibleUsed, deltaNonPreemptibleUsed) for _, resName := range quotav1.IsNegative(qi.CalculateInfo.Used) { @@ -258,6 +285,17 @@ func (qi *QuotaInfo) addUsedNonNegativeNoLock(delta, deltaNonPreemptibleUsed v1. for _, resName := range quotav1.IsNegative(qi.CalculateInfo.NonPreemptibleUsed) { qi.CalculateInfo.NonPreemptibleUsed[resName] = createQuantity(0, resName) } + + if isSelfUsed { + qi.CalculateInfo.ParentSelfUsed = quotav1.Add(qi.CalculateInfo.ParentSelfUsed, delta) + for _, resName := range quotav1.IsNegative(qi.CalculateInfo.ParentSelfUsed) { + qi.CalculateInfo.ParentSelfUsed[resName] = createQuantity(0, resName) + } + qi.CalculateInfo.ParentSelfNonPreemptibleUsed = quotav1.Add(qi.CalculateInfo.ParentSelfNonPreemptibleUsed, deltaNonPreemptibleUsed) + for _, resName := range quotav1.IsNegative(qi.CalculateInfo.ParentSelfNonPreemptibleUsed) { + qi.CalculateInfo.ParentSelfNonPreemptibleUsed[resName] = createQuantity(0, resName) + } + } } func (qi *QuotaInfo) addAllocatedQuotaNoLock(delta v1.ResourceList) { @@ -313,6 +351,30 @@ func (qi *QuotaInfo) GetNonPreemptibleRequest() v1.ResourceList { return qi.CalculateInfo.NonPreemptibleRequest.DeepCopy() } +func (qi *QuotaInfo) GetParentSelfRequest() v1.ResourceList { + qi.lock.Lock() + defer qi.lock.Unlock() + return qi.CalculateInfo.ParentSelfRequest.DeepCopy() +} + +func (qi *QuotaInfo) GetParentSelfUsed() v1.ResourceList { + qi.lock.Lock() + defer qi.lock.Unlock() + return qi.CalculateInfo.ParentSelfUsed.DeepCopy() +} + +func (qi *QuotaInfo) GetParentSelfNonPreemptibleUsed() v1.ResourceList { + qi.lock.Lock() + defer qi.lock.Unlock() + return qi.CalculateInfo.ParentSelfNonPreemptibleUsed.DeepCopy() +} + +func (qi *QuotaInfo) GetParentSelfNonPreemptibleRequest() v1.ResourceList { + qi.lock.Lock() + defer qi.lock.Unlock() + return qi.CalculateInfo.ParentSelfNonPreemptibleRequest.DeepCopy() +} + func (qi *QuotaInfo) GetRuntime() v1.ResourceList { qi.lock.Lock() defer qi.lock.Unlock() @@ -362,6 +424,10 @@ func (qi *QuotaInfo) clearForResetNoLock() { qi.CalculateInfo.ChildRequest = v1.ResourceList{} qi.CalculateInfo.Guaranteed = v1.ResourceList{} qi.CalculateInfo.Allocated = v1.ResourceList{} + qi.CalculateInfo.ParentSelfUsed = v1.ResourceList{} + qi.CalculateInfo.ParentSelfRequest = v1.ResourceList{} + qi.CalculateInfo.ParentSelfNonPreemptibleUsed = v1.ResourceList{} + qi.CalculateInfo.ParentSelfNonPreemptibleRequest = v1.ResourceList{} qi.RuntimeVersion = 0 } diff --git a/pkg/scheduler/plugins/elasticquota/core/quota_summary.go b/pkg/scheduler/plugins/elasticquota/core/quota_summary.go index aae57e1ed..470e9207c 100644 --- a/pkg/scheduler/plugins/elasticquota/core/quota_summary.go +++ b/pkg/scheduler/plugins/elasticquota/core/quota_summary.go @@ -33,18 +33,22 @@ type QuotaInfoSummary struct { AllowLentResource bool `json:"allowLentResource"` Tree string `json:"tree"` - Max v1.ResourceList `json:"max"` - Min v1.ResourceList `json:"min"` - AutoScaleMin v1.ResourceList `json:"autoScaleMin"` - Used v1.ResourceList `json:"used"` - NonPreemptibleUsed v1.ResourceList `json:"nonPreemptibleUsed"` - Request v1.ResourceList `json:"request"` - NonPreemptibleRequest v1.ResourceList `json:"nonPreemptibleRequest"` - SharedWeight v1.ResourceList `json:"sharedWeight"` - Runtime v1.ResourceList `json:"runtime"` - ChildRequest v1.ResourceList `json:"childRequest"` - Allocated v1.ResourceList `json:"allocated"` - Guaranteed v1.ResourceList `json:"guaranteed"` + Max v1.ResourceList `json:"max"` + Min v1.ResourceList `json:"min"` + AutoScaleMin v1.ResourceList `json:"autoScaleMin"` + Used v1.ResourceList `json:"used"` + NonPreemptibleUsed v1.ResourceList `json:"nonPreemptibleUsed"` + Request v1.ResourceList `json:"request"` + NonPreemptibleRequest v1.ResourceList `json:"nonPreemptibleRequest"` + SharedWeight v1.ResourceList `json:"sharedWeight"` + Runtime v1.ResourceList `json:"runtime"` + ChildRequest v1.ResourceList `json:"childRequest"` + Allocated v1.ResourceList `json:"allocated"` + Guaranteed v1.ResourceList `json:"guaranteed"` + ParentSelfUsed v1.ResourceList `json:"parentSelfUsed"` + ParentSelfNonPreemptibleUsed v1.ResourceList `json:"parentSelfNonPreemptibleUsed"` + ParentSelfRequest v1.ResourceList `json:"parentSelfRequest"` + ParentSelfNonPreemptibleRequest v1.ResourceList `json:"parentSelfNonPreemptibleRequest"` PodCache map[string]*SimplePodInfo `json:"podCache,omitempty"` } diff --git a/pkg/scheduler/plugins/elasticquota/core/runtime_quota_calculator_test.go b/pkg/scheduler/plugins/elasticquota/core/runtime_quota_calculator_test.go index ed6526a77..0e35e9f30 100644 --- a/pkg/scheduler/plugins/elasticquota/core/runtime_quota_calculator_test.go +++ b/pkg/scheduler/plugins/elasticquota/core/runtime_quota_calculator_test.go @@ -45,7 +45,7 @@ func TestQuotaInfo_GetLimitRequest(t *testing.T) { assertObj.Equal(*resource.NewQuantity(1000, resource.BinarySI), quotaInfo.getLimitRequestNoLock()[corev1.ResourceMemory]) req2 := createResourceList(100, 1000) - quotaInfo.addRequestNonNegativeNoLock(req2, req2) + quotaInfo.addRequestNonNegativeNoLock(req2, req2, false) assertObj.Equal(*resource.NewQuantity(2000, resource.BinarySI), quotaInfo.getLimitRequestNoLock()[corev1.ResourceMemory]) } @@ -57,8 +57,8 @@ func TestQuotaInfo_AddRequestNonNegativeNoLock(t *testing.T) { Used: createResourceList(40, 40), }, } - quotaInfo.addRequestNonNegativeNoLock(req1, req1) - quotaInfo.addUsedNonNegativeNoLock(req1, createResourceList(0, 0)) + quotaInfo.addRequestNonNegativeNoLock(req1, req1, false) + quotaInfo.addUsedNonNegativeNoLock(req1, createResourceList(0, 0), false) assert.Equal(t, quotaInfo.CalculateInfo.Request, createResourceList(0, 0)) assert.Equal(t, quotaInfo.CalculateInfo.Used, createResourceList(0, 0)) } @@ -217,7 +217,7 @@ func TestRuntimeQuotaCalculator_UpdateOneGroupMaxQuota(t *testing.T) { newMax := createResourceList(200, 9000) request := createResourceList(30, 3000) - quotaInfo.addRequestNonNegativeNoLock(request, request) + quotaInfo.addRequestNonNegativeNoLock(request, request, false) assert.Equal(t, request, quotaInfo.CalculateInfo.Request) qtw.setClusterTotalResource(max) @@ -309,7 +309,7 @@ func TestRuntimeQuotaCalculator_UpdateOneGroupRequest(t *testing.T) { request := createResourceList(int64(i*10), int64(i*1000)) quotaName := fmt.Sprintf("test-%d", i) quotaInfo := createQuotaInfoWithRes(quotaName, max, min) - quotaInfo.addRequestNonNegativeNoLock(request, request) + quotaInfo.addRequestNonNegativeNoLock(request, request, false) qtw.updateOneGroupMaxQuota(quotaInfo) qtw.updateOneGroupMinQuota(quotaInfo)