wilfred-s commented on code in PR #563:
URL: https://github.com/apache/yunikorn-core/pull/563#discussion_r1236305672


##########
pkg/scheduler/ugm/manager.go:
##########
@@ -35,23 +35,24 @@ var m *Manager
 
 const maxresources = "maxresources"
 const maxapplications = "maxapplications"
+const wildcard = "*"
 
 // Manager implements tracker. A User Group Manager to track the usage for 
both user and groups.
 // Holds object of both user and group trackers
 type Manager struct {
-       userTrackers      map[string]*UserTracker
-       groupTrackers     map[string]*GroupTracker
-       userLimitsConfig  map[string]map[string]map[string]interface{} // Hold 
limits settings of user * queue path
-       groupLimitsConfig map[string]map[string]map[string]interface{} // Hold 
limits settings of group * queue path
+       userTrackers              map[string]*UserTracker
+       groupTrackers             map[string]*GroupTracker
+       userWildCardLimitsConfig  map[string]map[string]interface{} // Hold 
limits settings of user '*'
+       groupWildCardLimitsConfig map[string]map[string]interface{} // Hold 
limits settings of group '*'

Review Comment:
   Simplify this: introduce a struct type that has two entries. Resource and 
uint64 to store the wildcard settings in. Store that struct in the map. That 
safes one indirection and the continuous conversion of the limit object's 
`map[string]string` to a resource.



##########
pkg/scheduler/ugm/queue_tracker.go:
##########
@@ -31,38 +31,141 @@ import (
 
 type QueueTracker struct {
        queueName           string
+       parent              *QueueTracker
+       queuePath           string
        resourceUsage       *resources.Resource
        runningApplications map[string]bool
-       maxResourceUsage    *resources.Resource
+       maxResources        *resources.Resource
        maxRunningApps      uint64
        childQueueTrackers  map[string]*QueueTracker
 }
 
 func newRootQueueTracker() *QueueTracker {
-       return newQueueTracker(configs.RootQueue)
+       qt := newQueueTracker(configs.RootQueue, nil)
+       return qt
 }
 
-func newQueueTracker(queueName string) *QueueTracker {
-       log.Logger().Debug("Creating queue tracker object for queue",
-               zap.String("queue", queueName))
+func newQueueTracker(queueName string, parent *QueueTracker) *QueueTracker {
        queueTracker := &QueueTracker{
                queueName:           queueName,
+               parent:              parent,
                resourceUsage:       resources.NewResource(),
                runningApplications: make(map[string]bool),
+               maxResources:        resources.NewResource(),
+               maxRunningApps:      0,
                childQueueTrackers:  make(map[string]*QueueTracker),
        }
+       parentQueueName := ""
+       if parent != nil {
+               queueTracker.queuePath = queueTracker.parent.queuePath + 
configs.DOT + queueName
+               parentQueueName = parent.queueName
+       } else if queueName == configs.RootQueue {
+               queueTracker.queuePath = configs.RootQueue
+       }
+       log.Logger().Debug("Created queue tracker object for queue",
+               zap.String("queue", queueName),
+               zap.String("parent", parentQueueName),
+               zap.String("queue path ", queueTracker.queuePath))
        return queueTracker
 }
 
-func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, usage *resources.Resource) error {
+type trackingType int
+
+const (
+       none trackingType = iota
+       user
+       group
+)
+
+func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, trackType trackingType, usage *resources.Resource) bool {
        log.Logger().Debug("Increasing resource usage",
+               zap.Int("tracking type", int(trackType)),
                zap.String("queue path", queuePath),
                zap.String("application", applicationID),
                zap.Stringer("resource", usage))
        if queuePath == "" || applicationID == "" || usage == nil {
-               return fmt.Errorf("mandatory parameters are missing. queuepath: 
%s, application id: %s, resource usage: %s",
-                       queuePath, applicationID, usage.String())
+               return false
+       }
+
+       finalResourceUsage := qt.resourceUsage.Clone()
+       finalResourceUsage.AddTo(usage)
+       wildCardQuotaExceeded := false
+
+       // Are there any settings for specific user/group? If not, try wild 
card settings
+       if int(qt.maxRunningApps) == 0 && 
resources.Equals(resources.NewResource(), qt.maxResources) {
+               // Is there any wild card settings? Do we need to apply 
enforcement checks using wild card limit settings?
+               var config map[string]interface{}
+               if trackType == user {
+                       config = m.getUserWildCardLimitsConfig(qt.queuePath)
+               } else if trackType == group {
+                       config = m.getGroupWildCardLimitsConfig(qt.queuePath)
+               }
+               if config != nil {
+                       var maxResources map[string]string
+                       var maxApplications uint64
+                       var ok bool
+                       if maxApplications, ok = 
config[maxapplications].(uint64); !ok {
+                               log.Logger().Debug("Problem in using the wild 
card limit max application settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.Int("tracking type", 
int(trackType)),
+                                       zap.Any("max applications ", 
config[maxapplications]))
+                       }
+                       if maxResources, ok = 
config[maxresources].(map[string]string); !ok {
+                               log.Logger().Debug("Problem in using the wild 
card limit max resources settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.Int("tracking type", 
int(trackType)),
+                                       zap.Any("max applications ", 
config[maxresources]))
+                       }
+                       var maxResource *resources.Resource
+                       var err error
+                       if maxResource, err = 
resources.NewResourceFromConf(maxResources); err != nil {
+                               log.Logger().Debug("Problem in using the wild 
card limit max resources settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.String("max resources after 
casting", maxResource.String()),
+                                       zap.Error(err))
+                               return false
+                       }
+                       wildCardQuotaExceeded = (maxApplications != 0 && 
len(qt.runningApplications)+1 > int(maxApplications)) || 
(!resources.Equals(resources.NewResource(), maxResource) && 
resources.StrictlyGreaterThan(finalResourceUsage, maxResource))
+                       log.Logger().Debug("using wild card limit settings as 
user/group specific limit settings not set",
+                               zap.Int("tracking type", int(trackType)),
+                               zap.String("queue path", queuePath),
+                               zap.Uint64("wild card max running apps", 
maxApplications),
+                               zap.String("wild card max resources", 
maxResource.String()),
+                               zap.Bool("wild card quota exceeded", 
wildCardQuotaExceeded))
+               }

Review Comment:
   return here if not passed: wildcard has been checked and no specific quota 
was set.



##########
pkg/scheduler/ugm/queue_tracker.go:
##########
@@ -48,20 +49,36 @@ func newQueueTracker(queueName string) *QueueTracker {
                queueName:           queueName,
                resourceUsage:       resources.NewResource(),
                runningApplications: make(map[string]bool),
+               maxResourceUsage:    resources.NewResource(),
+               maxRunningApps:      0,
                childQueueTrackers:  make(map[string]*QueueTracker),
        }
        return queueTracker
 }
 
-func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, usage *resources.Resource) error {
+func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, usage *resources.Resource) bool {
        log.Logger().Debug("Increasing resource usage",
                zap.String("queue path", queuePath),
                zap.String("application", applicationID),
                zap.Stringer("resource", usage))
        if queuePath == "" || applicationID == "" || usage == nil {
-               return fmt.Errorf("mandatory parameters are missing. queuepath: 
%s, application id: %s, resource usage: %s",
-                       queuePath, applicationID, usage.String())
+               return false
+       }

Review Comment:
   agree remove the check



##########
pkg/scheduler/ugm/queue_tracker.go:
##########
@@ -31,38 +31,141 @@ import (
 
 type QueueTracker struct {
        queueName           string
+       parent              *QueueTracker
+       queuePath           string
        resourceUsage       *resources.Resource
        runningApplications map[string]bool
-       maxResourceUsage    *resources.Resource
+       maxResources        *resources.Resource
        maxRunningApps      uint64
        childQueueTrackers  map[string]*QueueTracker
 }
 
 func newRootQueueTracker() *QueueTracker {
-       return newQueueTracker(configs.RootQueue)
+       qt := newQueueTracker(configs.RootQueue, nil)
+       return qt
 }
 
-func newQueueTracker(queueName string) *QueueTracker {
-       log.Logger().Debug("Creating queue tracker object for queue",
-               zap.String("queue", queueName))
+func newQueueTracker(queueName string, parent *QueueTracker) *QueueTracker {
        queueTracker := &QueueTracker{
                queueName:           queueName,
+               parent:              parent,
                resourceUsage:       resources.NewResource(),
                runningApplications: make(map[string]bool),
+               maxResources:        resources.NewResource(),
+               maxRunningApps:      0,
                childQueueTrackers:  make(map[string]*QueueTracker),
        }
+       parentQueueName := ""
+       if parent != nil {
+               queueTracker.queuePath = queueTracker.parent.queuePath + 
configs.DOT + queueName
+               parentQueueName = parent.queueName
+       } else if queueName == configs.RootQueue {
+               queueTracker.queuePath = configs.RootQueue
+       }
+       log.Logger().Debug("Created queue tracker object for queue",
+               zap.String("queue", queueName),
+               zap.String("parent", parentQueueName),
+               zap.String("queue path ", queueTracker.queuePath))
        return queueTracker
 }
 
-func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, usage *resources.Resource) error {
+type trackingType int
+
+const (
+       none trackingType = iota
+       user
+       group
+)
+
+func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, trackType trackingType, usage *resources.Resource) bool {
        log.Logger().Debug("Increasing resource usage",
+               zap.Int("tracking type", int(trackType)),
                zap.String("queue path", queuePath),
                zap.String("application", applicationID),
                zap.Stringer("resource", usage))
        if queuePath == "" || applicationID == "" || usage == nil {
-               return fmt.Errorf("mandatory parameters are missing. queuepath: 
%s, application id: %s, resource usage: %s",
-                       queuePath, applicationID, usage.String())
+               return false
+       }
+
+       finalResourceUsage := qt.resourceUsage.Clone()
+       finalResourceUsage.AddTo(usage)
+       wildCardQuotaExceeded := false
+

Review Comment:
   is this a new app to add to the list of running applications?
   ```
   existingApp := runningApplications[appId]
   ```
   Only check maxRunningApps within range if `existingApp == false`



##########
pkg/scheduler/ugm/queue_tracker.go:
##########
@@ -31,38 +31,141 @@ import (
 
 type QueueTracker struct {
        queueName           string
+       parent              *QueueTracker
+       queuePath           string
        resourceUsage       *resources.Resource
        runningApplications map[string]bool
-       maxResourceUsage    *resources.Resource
+       maxResources        *resources.Resource
        maxRunningApps      uint64
        childQueueTrackers  map[string]*QueueTracker
 }
 
 func newRootQueueTracker() *QueueTracker {
-       return newQueueTracker(configs.RootQueue)
+       qt := newQueueTracker(configs.RootQueue, nil)
+       return qt
 }
 
-func newQueueTracker(queueName string) *QueueTracker {
-       log.Logger().Debug("Creating queue tracker object for queue",
-               zap.String("queue", queueName))
+func newQueueTracker(queueName string, parent *QueueTracker) *QueueTracker {
        queueTracker := &QueueTracker{
                queueName:           queueName,
+               parent:              parent,
                resourceUsage:       resources.NewResource(),
                runningApplications: make(map[string]bool),
+               maxResources:        resources.NewResource(),
+               maxRunningApps:      0,
                childQueueTrackers:  make(map[string]*QueueTracker),
        }
+       parentQueueName := ""
+       if parent != nil {
+               queueTracker.queuePath = queueTracker.parent.queuePath + 
configs.DOT + queueName
+               parentQueueName = parent.queueName
+       } else if queueName == configs.RootQueue {
+               queueTracker.queuePath = configs.RootQueue
+       }
+       log.Logger().Debug("Created queue tracker object for queue",
+               zap.String("queue", queueName),
+               zap.String("parent", parentQueueName),
+               zap.String("queue path ", queueTracker.queuePath))
        return queueTracker
 }
 
-func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, usage *resources.Resource) error {
+type trackingType int
+
+const (
+       none trackingType = iota
+       user
+       group
+)
+
+func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, trackType trackingType, usage *resources.Resource) bool {
        log.Logger().Debug("Increasing resource usage",
+               zap.Int("tracking type", int(trackType)),
                zap.String("queue path", queuePath),
                zap.String("application", applicationID),
                zap.Stringer("resource", usage))
        if queuePath == "" || applicationID == "" || usage == nil {
-               return fmt.Errorf("mandatory parameters are missing. queuepath: 
%s, application id: %s, resource usage: %s",
-                       queuePath, applicationID, usage.String())
+               return false
+       }
+
+       finalResourceUsage := qt.resourceUsage.Clone()
+       finalResourceUsage.AddTo(usage)
+       wildCardQuotaExceeded := false
+
+       // Are there any settings for specific user/group? If not, try wild 
card settings
+       if int(qt.maxRunningApps) == 0 && 
resources.Equals(resources.NewResource(), qt.maxResources) {
+               // Is there any wild card settings? Do we need to apply 
enforcement checks using wild card limit settings?
+               var config map[string]interface{}
+               if trackType == user {
+                       config = m.getUserWildCardLimitsConfig(qt.queuePath)
+               } else if trackType == group {
+                       config = m.getGroupWildCardLimitsConfig(qt.queuePath)
+               }
+               if config != nil {
+                       var maxResources map[string]string
+                       var maxApplications uint64
+                       var ok bool
+                       if maxApplications, ok = 
config[maxapplications].(uint64); !ok {
+                               log.Logger().Debug("Problem in using the wild 
card limit max application settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.Int("tracking type", 
int(trackType)),
+                                       zap.Any("max applications ", 
config[maxapplications]))
+                       }
+                       if maxResources, ok = 
config[maxresources].(map[string]string); !ok {
+                               log.Logger().Debug("Problem in using the wild 
card limit max resources settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.Int("tracking type", 
int(trackType)),
+                                       zap.Any("max applications ", 
config[maxresources]))
+                       }
+                       var maxResource *resources.Resource
+                       var err error
+                       if maxResource, err = 
resources.NewResourceFromConf(maxResources); err != nil {
+                               log.Logger().Debug("Problem in using the wild 
card limit max resources settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.String("max resources after 
casting", maxResource.String()),
+                                       zap.Error(err))
+                               return false
+                       }
+                       wildCardQuotaExceeded = (maxApplications != 0 && 
len(qt.runningApplications)+1 > int(maxApplications)) || 
(!resources.Equals(resources.NewResource(), maxResource) && 
resources.StrictlyGreaterThan(finalResourceUsage, maxResource))
+                       log.Logger().Debug("using wild card limit settings as 
user/group specific limit settings not set",
+                               zap.Int("tracking type", int(trackType)),
+                               zap.String("queue path", queuePath),
+                               zap.Uint64("wild card max running apps", 
maxApplications),
+                               zap.String("wild card max resources", 
maxResource.String()),
+                               zap.Bool("wild card quota exceeded", 
wildCardQuotaExceeded))
+               }
+       }
+
+       // apply user/group specific limit settings set if configured, 
otherwise use wild card limit settings
+       if (int(qt.maxRunningApps) != 0 && 
!resources.Equals(resources.NewResource(), qt.maxResources)) || 
wildCardQuotaExceeded {

Review Comment:
   no casting to int just use the uint64



##########
pkg/scheduler/ugm/queue_tracker.go:
##########
@@ -31,38 +31,141 @@ import (
 
 type QueueTracker struct {
        queueName           string
+       parent              *QueueTracker
+       queuePath           string
        resourceUsage       *resources.Resource
        runningApplications map[string]bool
-       maxResourceUsage    *resources.Resource
+       maxResources        *resources.Resource
        maxRunningApps      uint64
        childQueueTrackers  map[string]*QueueTracker
 }
 
 func newRootQueueTracker() *QueueTracker {
-       return newQueueTracker(configs.RootQueue)
+       qt := newQueueTracker(configs.RootQueue, nil)
+       return qt
 }
 
-func newQueueTracker(queueName string) *QueueTracker {
-       log.Logger().Debug("Creating queue tracker object for queue",
-               zap.String("queue", queueName))
+func newQueueTracker(queueName string, parent *QueueTracker) *QueueTracker {
        queueTracker := &QueueTracker{
                queueName:           queueName,
+               parent:              parent,
                resourceUsage:       resources.NewResource(),
                runningApplications: make(map[string]bool),
+               maxResources:        resources.NewResource(),
+               maxRunningApps:      0,
                childQueueTrackers:  make(map[string]*QueueTracker),
        }
+       parentQueueName := ""
+       if parent != nil {
+               queueTracker.queuePath = queueTracker.parent.queuePath + 
configs.DOT + queueName
+               parentQueueName = parent.queueName
+       } else if queueName == configs.RootQueue {
+               queueTracker.queuePath = configs.RootQueue
+       }
+       log.Logger().Debug("Created queue tracker object for queue",
+               zap.String("queue", queueName),
+               zap.String("parent", parentQueueName),
+               zap.String("queue path ", queueTracker.queuePath))
        return queueTracker
 }
 
-func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, usage *resources.Resource) error {
+type trackingType int
+
+const (
+       none trackingType = iota
+       user
+       group
+)
+
+func (qt *QueueTracker) increaseTrackedResource(queuePath string, 
applicationID string, trackType trackingType, usage *resources.Resource) bool {
        log.Logger().Debug("Increasing resource usage",
+               zap.Int("tracking type", int(trackType)),
                zap.String("queue path", queuePath),
                zap.String("application", applicationID),
                zap.Stringer("resource", usage))
        if queuePath == "" || applicationID == "" || usage == nil {
-               return fmt.Errorf("mandatory parameters are missing. queuepath: 
%s, application id: %s, resource usage: %s",
-                       queuePath, applicationID, usage.String())
+               return false
+       }
+
+       finalResourceUsage := qt.resourceUsage.Clone()
+       finalResourceUsage.AddTo(usage)
+       wildCardQuotaExceeded := false
+
+       // Are there any settings for specific user/group? If not, try wild 
card settings
+       if int(qt.maxRunningApps) == 0 && 
resources.Equals(resources.NewResource(), qt.maxResources) {
+               // Is there any wild card settings? Do we need to apply 
enforcement checks using wild card limit settings?
+               var config map[string]interface{}
+               if trackType == user {
+                       config = m.getUserWildCardLimitsConfig(qt.queuePath)
+               } else if trackType == group {
+                       config = m.getGroupWildCardLimitsConfig(qt.queuePath)
+               }
+               if config != nil {
+                       var maxResources map[string]string
+                       var maxApplications uint64
+                       var ok bool
+                       if maxApplications, ok = 
config[maxapplications].(uint64); !ok {
+                               log.Logger().Debug("Problem in using the wild 
card limit max application settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.Int("tracking type", 
int(trackType)),
+                                       zap.Any("max applications ", 
config[maxapplications]))
+                       }
+                       if maxResources, ok = 
config[maxresources].(map[string]string); !ok {
+                               log.Logger().Debug("Problem in using the wild 
card limit max resources settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.Int("tracking type", 
int(trackType)),
+                                       zap.Any("max applications ", 
config[maxresources]))
+                       }
+                       var maxResource *resources.Resource
+                       var err error
+                       if maxResource, err = 
resources.NewResourceFromConf(maxResources); err != nil {
+                               log.Logger().Debug("Problem in using the wild 
card limit max resources settings.",
+                                       zap.String("queue path", queuePath),
+                                       zap.String("max resources after 
casting", maxResource.String()),
+                                       zap.Error(err))
+                               return false
+                       }
+                       wildCardQuotaExceeded = (maxApplications != 0 && 
len(qt.runningApplications)+1 > int(maxApplications)) || 
(!resources.Equals(resources.NewResource(), maxResource) && 
resources.StrictlyGreaterThan(finalResourceUsage, maxResource))
+                       log.Logger().Debug("using wild card limit settings as 
user/group specific limit settings not set",
+                               zap.Int("tracking type", int(trackType)),
+                               zap.String("queue path", queuePath),
+                               zap.Uint64("wild card max running apps", 
maxApplications),
+                               zap.String("wild card max resources", 
maxResource.String()),
+                               zap.Bool("wild card quota exceeded", 
wildCardQuotaExceeded))
+               }
+       }
+
+       // apply user/group specific limit settings set if configured, 
otherwise use wild card limit settings
+       if (int(qt.maxRunningApps) != 0 && 
!resources.Equals(resources.NewResource(), qt.maxResources)) || 
wildCardQuotaExceeded {
+               log.Logger().Debug("applying enforcement checks using limit 
settings",
+                       zap.Int("tracking type", int(trackType)),
+                       zap.String("queue path", queuePath),
+                       zap.Uint64("max running apps", qt.maxRunningApps),
+                       zap.String("max resources", qt.maxResources.String()),
+                       zap.Bool("wild card quota exceeded", 
wildCardQuotaExceeded))
+               if (len(qt.runningApplications)+1 > int(qt.maxRunningApps) || 
resources.StrictlyGreaterThan(finalResourceUsage, qt.maxResources)) || 
wildCardQuotaExceeded {
+                       log.Logger().Warn("Unable to increase resource usage as 
allowing new application to run would exceed either configured max applications 
or max resources limit of specific user/group or wild card user/group",
+                               zap.String("queue path", queuePath),
+                               zap.Int("tracking type", int(trackType)),
+                               zap.Int("current running applications", 
len(qt.runningApplications)),
+                               zap.Int("max running applications", 
int(qt.maxRunningApps)),
+                               zap.String("current resource usage", 
qt.resourceUsage.String()),
+                               zap.String("max resource usage", 
qt.maxResources.String()))
+                       return false
+               }
+       }
+
+       childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+       if childQueuePath != "" {
+               if qt.childQueueTrackers[immediateChildQueueName] == nil {
+                       qt.childQueueTrackers[immediateChildQueueName] = 
newQueueTracker(immediateChildQueueName, qt)
+               }
+               result := 
qt.childQueueTrackers[immediateChildQueueName].increaseTrackedResource(childQueuePath,
 applicationID, trackType, usage)
+               if !result {
+                       return false
+               }

Review Comment:
   use
   ```
   if allowed := qt....; !allowed {
    return allowed
   }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to